From nobody Wed Jun 17 01:38:28 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020082.outbound.protection.outlook.com [52.101.196.82]) (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 7DB4C3DB625; Tue, 21 Apr 2026 14:56:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.82 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783402; cv=fail; b=GMUu7RER7ie5av4FjsPbnodKA+1jdDAC7iyLOD7zAeSgH+nYygxTQmhvNv8bVV4+WEeTQKUTwC6hsXccqOeP6z6SlUVsve08sUXhCKj7wITzyNC5C/jjrZVWBt9EsRIhp0m6nSWWwBR7Lnhk2NmGL+lWB1P1cjvAyGAJfbO4W3Q= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783402; c=relaxed/simple; bh=nYKQK/f1KfskLdodznB/5NT4h/cZos/SolizpGrj0LE=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=lE3rHXKCrAvdEDWJWWAmfzL1jMk4lwi3IjNVClELcDDqcEyWkSoJpRm4nxn7200rIh/EpKWtBjQPoyXCjKl9E50ypc7r2LBEr3jzIVAgKj9P2C9rreFIBTfOdtmXclc6Lj8qAiHZ3/asiMqKsgZVJqS3/5DZlk7wwF/hcWAcaw4= 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=VqbSJBQI; arc=fail smtp.client-ip=52.101.196.82 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="VqbSJBQI" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ij/bqBuc40tPgaS6OszEXxbxBRww/YcKm6uJ1f6kYZQYW8H2TpWmOAuv3dUX7dRpGXPQSE1eoJay07h8q9clJ3NVdBBAvV3HjeHhYn5p4cmRBPbBxTdC84Gr/oAZn8Nph5IrgOH2h9ajr3BpiePN98VtI4jRxT3qpmfT2X0WWuym0iS5/clZ+KeuBUsTGWdCfBNwEQfVlbFIucntpRrlCE6ZnOJ/WmoUfyRw57UFgaHviFwMXEoNjBGbjqnrOTfF+7r63I5Hlnau3NOwPwNKr1H36AL9sA8wHT9EqqKCTxMpnhmjygaWSzaayD+rL/YCluIYUmY/yRUy0rAy1xpJwg== 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=KherrrE+rsrXm3BlkG4oiDUH5/nddaBLxhmqGt2+OeY=; b=acQCdL3MUP1VUWaAG4K/yX/7sUympzQHF9seVUbdmcx+jM/DjeEoJraZcdmtNELaqiTjPKqDcZv/EauBwKtjx+GYGYET73eDGpltpslrMii+g2daKmNLHamcrjFQbg+IbItIii5sc1IzLC67x6hY1w3PUKiZh5171Z7GeXtluzS0gcjmKd2C1UpWW0AvvDSLHnsg9794Doz2A7XZ9jk9m+Yg9eIXtNq/pQHDm8tY0cScM62FCkm2jwGu7mcbXw14Jn93GKuXANwo4FS8Fl8g/H+aEwGwRPioU3Jrfp7OVcUHtSkZbFcvykFlRHVeA3NtGgs7XYpocqroABmHhQLFmA== 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=KherrrE+rsrXm3BlkG4oiDUH5/nddaBLxhmqGt2+OeY=; b=VqbSJBQI3SvwFDkI62FBhved/I9643ZWttr/MB6Kt9H1iG9pp5K2+JlYn2Cg/FpNPMvQdMCzz4c9Lahs1pSHkwaGRSsEIjpRiD8CwCSkJAtYgnSCPWoQQIcws0dFxiF49f+INdGpfIBeNUxhUi6iiptR/2sxAT+Ccw5oixcOPvs= 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 CWLP265MB5523.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b9::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.16; Tue, 21 Apr 2026 14:56:27 +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.20.9846.016; Tue, 21 Apr 2026 14:56:27 +0000 From: Gary Guo Date: Tue, 21 Apr 2026 15:56:12 +0100 Subject: [PATCH v2 01/11] rust: io: generalize `MmioRaw` to pointer to arbitrary type Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-1-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=8434; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=nYKQK/f1KfskLdodznB/5NT4h/cZos/SolizpGrj0LE=; b=OaG5mFrZyUJqCnGEj3sHwSoJsPGCebrOKCATdGc3MWO9XHxsjhqyRuWhIIAwXdsQrGvIpbYtE KSXJicQWrJUAzNUDuroHrvxyA8+GIfotk7Sz5peuVeIJbWnKM5pqiER X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5523:EE_ X-MS-Office365-Filtering-Correlation-Id: 4fe97c69-24bd-4ecd-b278-08de9fb62a24 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: qebbT1Q96VGI7ZSMcCimdrG9Fuy/tVc3tBIq2V0SvarRhDrIwjpd/CyachTAeM4lN8sD5u96/eZ3sFUVHoRbJ8JaFDbnXbIgLftRDEiUhEVyMYFbgBqwBkU4CMJnTqwSHSg3nMfi1sn0QNl7zJ2xN7LXoQCBUlIRZ7uz9kPFOftQagZoWY7lL48wP3BpmlSs2DlWgufaYz7ghI1+cbafFkTSPB/PhaEVzzT6Ex1MEEE1hp7f41D6M5LHorjjd3JXnTe7gXxtEQiDGzQsIGzVltxF02bYEvUlPmwOUxz4PVaGy7YrWlnJDvoFiAOnWvxjCUpctEsrvVau9Cc8bzqvEvaz9Ul6yn5AfVu6K5XID9t9Mp5k503sOWVIY+bTF8iREOmPYxMGu2RkzcZReg1lwPyiqspyY0BWSxKQFz/kjHEy6ee1mDcAfoqexXFgmkTrDnwbFqsc90bGaVC4bOX4SWI3k1KDn7rTfekGGqbAF1+5UocCKLH1laGHqGn6GIC+XHOEwlCPW1ecVHCW7HrwELCjw0eIeSwf1tjusa6YsfKyaIj6VPS46iU1RzKnjiV1SOvFxz/iX+eIvczsrWu5XbtFnpT51YaDUKEL/vjhm3ZIbNLE2c8a7wby8zbcPq3RGyVwkG59Qf4IgW0YXS/kAnK36jYK6ODCtEC2rFQsFiJWlz5yYrL1kNGPHYa28OCkaBs5XMf7lBmUH2MXhxAD82jS4fbqB2xgIwPiWnACLTqA7IduA15l8mUahRdh98CndMOVn04qBMIL2ZKiqmnTqQ== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?SmRPcENsV3dwZndVa1NKQk8zUnJ3M2pMeDRIYVJPTThaQWxJRG9vOVkrbG1D?= =?utf-8?B?aVB4cDVzcm5OdGdLc2JEbWRuRjZRMDcwblpJNXBqYkp6OS9HR3pxeXRUcWxS?= =?utf-8?B?cEtPUFR3aDc4U0d4ZmgyR29UamMrenprLyt6VmNGMlkwWmlBOHdKeldUdlBk?= =?utf-8?B?Y01WM1JicEM2ZTBncElDVWtlZEQzYkVJQWtGblM4R3lWQXpEME9IWGE3UmNN?= =?utf-8?B?YnFtWUU1ZWsvaW1maUt2UjJWeVBZTmd2d1ltVk9meFVZcWxsUVZWcXhSTG11?= =?utf-8?B?ejhZUmJWWHBhN01MS1A5Sm5YOFBiRjAvbXBCUUVZaFp4Q1JIUWhpODNqQUNW?= =?utf-8?B?dDdWdXJiRmtaSHB3dVBHSDZiZDhGcUNxUHE0dVdJeHE1aHFLWm82aDJqNmdW?= =?utf-8?B?enA2cFZCR2VsRUlSOEErejE1c2FJNFJ5N3k5UVFkL0RkSkhBNFV0bE0wVDEz?= =?utf-8?B?eHFZUzB4UVI3RVJZWjlMWWtVallJdzVMQy9KZDhkdkY5RzFWZC92c3JDb3Rr?= =?utf-8?B?cDNVZDYyTlBxL1c5K2FVNVBXTCtZNFVmd3VyYTVQcVZxa0FncjNXYnQrQ0tk?= =?utf-8?B?ZjhlVy9LTSttUDVwQ0x1YUZQTFQ5MUIxYkZGaVNHWkNGZG0wS3RJRHN6SHp1?= =?utf-8?B?R1RtK3o1Mk0vQkRaMHRqd05wd0p1VGYzY2NmUXhuL0RTSjRrT1VkUWd0QUF0?= =?utf-8?B?NGF0SEZXVng0UnQ2NmZWMnh3VnhjK0k4Ym1MRDZTUXlxYWM2ejdMVzZPbkhS?= =?utf-8?B?SHA4cWs3dEMvZXkxNWRXZDdueHNURXJPWThsYU9IMEgwaDByYXBsVmdlMWZG?= =?utf-8?B?RkhnVG80Z0lISHhtaGsvSmpEV1hGTjZwR1BzeDVQVU5EVmtEcVBGaHJIbnoz?= =?utf-8?B?RFFYMXUzUVRSMVR5WHFKVVhVaVQ3N3VrVmR1UXhnZXc0YW0vMEc0RFRaMXQ3?= =?utf-8?B?WFJnakhQYzhSQXdmRXlWVEpacEpZd2xTV3JEWDJRV1dpelhzYmk0Uysvb0FT?= =?utf-8?B?aVFSaldDVlVtSXFzdEhsVjQ3L3RrVHlLL3ppOEZ5emQ0T0c2aHRTUHllSUJl?= =?utf-8?B?TDYxZk1ycSt1TG1pWVUyeEczZTY5V3RVRk9HbmIxRU9ObHdCZWw2L1NJT2Vw?= =?utf-8?B?VHh3SkQ0UXlXTjlyR0gzTlA2OFhKTDhSWUp2alcwaUR6RUFldHdvVnptcEEv?= =?utf-8?B?bjlqdFRIcWtWa0JrOGQ3T2xMUlMvbkliYWZoL0ZsUTBjWjNsTk1YbkEzVzdS?= =?utf-8?B?RnREN0xzV0h2SHFqa3ZpNFExRll1djVvMy90TXdBM2dNdWx6ekdyaTN4ZFhu?= =?utf-8?B?VzQrbWlISUYxNlVGSlhtUndHWXNmR3l4em1xUmFCamhqdGt4WWtMMjFrYUhI?= =?utf-8?B?Y2xUUzNSRUk0aDl3eThuSnNBVU9TeXp2aGNnRjYwT1lDVm5OQ2R1TXFjUUta?= =?utf-8?B?cmFveFNZc3ZtdWlRMWFIVk1TOXpPY2pqRGtpRndjUW1XV3E2TG5sL045ckRS?= =?utf-8?B?bnByQkp5U1lvVnFJZnZwMWNyNzU3Wm1jVUhZN2RwK2RVamxRTitxSkRLMnEy?= =?utf-8?B?cTczdFNPcG1uTGtlcjc5Wk1wSnR2RDJ1S2diR3ZPNkRJMFhKWVlIVjBiMWd5?= =?utf-8?B?M2xFeGZEeXBSRWdvamxzOHRKNFhDYU0xbjZOZkVNRU9BU3dMM05JRmJTRHdO?= =?utf-8?B?VXFRTXp4bXJaNDF4dkVvZ3BJK0QwVkloVmhCbkQzVERwSXdFaWpoZWZtOWt5?= =?utf-8?B?TE1qS1Exc2NEV1RaMlo5Z3YxUEJkSXhIOVlnb29QRVFpQWp5VzJNREpxYVRl?= =?utf-8?B?Z29IdHhrSHFvZWYyWnZaNGV3blg2NTRlOTE3UWRLNlpodGJJRnRLU01aMXBw?= =?utf-8?B?RlFmYXdyY053a1R5MjVCR1BOeG94ZTczYy80Wk5aU3hVL1RsLy8zTWdWZU1m?= =?utf-8?B?L1VjdlhSaEc0OVo2STdOT0NnbmJkcmdmM2hUVnc0ZkdRM2FqcWJzcis1VjJz?= =?utf-8?B?b1VVNVAzVndSRGR3ZHdIZ2w5NDdTbGg5NGYzYUkxQU9oZkpBd1paWGh6dFFo?= =?utf-8?B?NkpEeTJJTWM2ak85SUFGSTJPQnNmRlFEQUFEWlJ0dVA2U21RKythSlZsT0xE?= =?utf-8?B?dXpvdHcwc0x5SHJtYXVVeVhFTEVqZ1FmWm51dGJadUVHS2ZjS3ZxaEpSMTNi?= =?utf-8?B?NkxBRWZvTGhwbndqSVB1RVQ2bDNyVVJUWkRKOGhhRTJaQUUxc2NYbFdvaVNu?= =?utf-8?B?QWF6Wm9iVlVPdmhQcWNPSzBZbVJkRmc1TFUyckZzZ05NY3F1ZFZQRXp1bk1n?= =?utf-8?B?Y1E1b1NWNjhhMzlQN2JZWDBSZUFibVJhemJFZDduY2QrdFl5V25zQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 4fe97c69-24bd-4ecd-b278-08de9fb62a24 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:27.3841 (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: VAOCeFOaBsvJtMWVG/hLi7gEv+m/cJdRJmxZ5chFbv59HHBvFBVRIM0U+nEraD/YAFLGMPADWMU5752fRcG6jA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5523 Conceptually, `MmioRaw` is just `__iomem *`, so it should work for any types. The existing use case where it represents a region of compile-time known minimum size and run-time known actual size is moved to a custom dynamic-sized type `Region` instead. The `maxsize` method is also renamed to `size` to reflect that it is the actual size (not a bound) of the region. Signed-off-by: Gary Guo Reviewed-by: Andreas Hindborg --- rust/kernel/devres.rs | 7 +++-- rust/kernel/io.rs | 84 ++++++++++++++++++++++++++++++++++++++++-------= ---- rust/kernel/io/mem.rs | 4 +-- rust/kernel/pci/io.rs | 4 +-- 4 files changed, 74 insertions(+), 25 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 9e5f93aed20c..65a4082122af 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -71,14 +71,15 @@ struct Inner { /// IoKnownSize, /// 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 @@ -93,7 +94,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 fcc7678fd9e3..d7f2145fa9b9 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -6,7 +6,8 @@ =20 use crate::{ bindings, - prelude::*, // + prelude::*, + ptr::KnownSize, // }; =20 pub mod mem; @@ -31,39 +32,85 @@ /// `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). +/// +/// The `SIZE` generic parameter indicate the minimum size of the region. +#[repr(transparent)] +pub struct Region { + inner: [u8], +} + +impl KnownSize for Region { + #[inline(always)] + fn size(p: *const Self) -> usize { + (p as *const [u8]).len() + } +} + /// 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. + addr: *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 { +// 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 { + addr: core::ptr::without_provenance_mut(addr), + } + } +} + +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 { + if size < SIZE { return Err(EINVAL); } =20 - Ok(Self { addr, maxsize }) + let addr =3D core::ptr::slice_from_raw_parts_mut::( + core::ptr::without_provenance_mut(addr), + size, + ) as *mut Region; + Ok(Self { addr }) } +} =20 +impl MmioRaw { /// Returns the base address of the MMIO region. #[inline] pub fn addr(&self) -> usize { - self.addr + self.addr.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.addr) } } =20 @@ -89,12 +136,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 @@ -109,7 +157,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)?)) /// } /// } /// @@ -139,7 +187,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 `offset` /// is valid within this region. @@ -767,7 +815,7 @@ fn addr(&self) -> usize { /// Returns the maximum size of this mapping. #[inline] fn maxsize(&self) -> usize { - self.0.maxsize() + self.0.size() } } =20 @@ -782,7 +830,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 7dc78d547f7a..9117d417f99c 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -231,7 +231,7 @@ fn deref(&self) -> &Self::Target { /// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid poin= ter to the /// start of the I/O memory mapped region. pub struct IoMem { - io: MmioRaw, + io: MmioRaw>, } =20 impl IoMem { @@ -266,7 +266,7 @@ fn ioremap(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)?; let io =3D IoMem { io }; =20 Ok(io) diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index ae78676c927f..0335b5068f69 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -148,7 +148,7 @@ impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSpac= e<'a, S> { /// memory mapped PCI BAR and its size. pub struct Bar { pdev: ARef, - io: MmioRaw, + io: MmioRaw>, num: i32, } =20 @@ -184,7 +184,7 @@ pub(super) fn new(pdev: &Device, num: u32, name: &CStr)= -> Result { 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.51.2 From nobody Wed Jun 17 01:38:28 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020082.outbound.protection.outlook.com [52.101.196.82]) (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 6C3EF3D6470; Tue, 21 Apr 2026 14:56:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.82 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783393; cv=fail; b=BsG2eaMp4fZmPXeiNMmse79wOnF1nB+gjF2srxwnAgL198n58WTLH4nGfKtPt9KUZprAZBN7CWB9j57SX3DuqENmLytwlMybLvCTNzr1qCvYVnFWoX0iiSZaHkNV7AWzxCWA1g8Ytoqqx0DhdEnXHJKAWs8fCLzmQhvouZepCYM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783393; c=relaxed/simple; bh=faM0ZpteUlJaNJZMTjGbI7mkrrDCMYhjEeLbY0rM2bo=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=aS83v+UqhyVKs0qa2F6Reef9HFld/ZR/iS4gpJknhMyCleiGqLZfcZEFx3VHkCpKOyE026TEVdDAeziKRdOdFz5tcxvtdAyuic0aw5rZKTWwyLNwE3YeY6qkvhfOZuwnLeqekwFHdaJ9y7JEIFQHRIGfH3ygJWOq4PZfRYFCb+4= 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=PdfOfMNU; arc=fail smtp.client-ip=52.101.196.82 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="PdfOfMNU" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=rFE60l3M40jhyfxqTJ3WbjshygQqWA03GuWwXsIA3vMo1n6x3Zl+F4HNxqVjsCbZsXO78DX3panenH+St1Ws5ckjw+nA7qEQwRw+jVijj+sg+0QNZpVhKv9eEC6NiAwmYBvopNUnPzDLnOoM6ctZY2bwYr1PrR184cE5JgHuZH1IAQ3baS2etrY/A/ZOvx1uPmV0B3TK+rCi3HHY8KBeNvlpIiYuBRfhgS7boN+S9i9jkeUns9Lx3/yx1ErGTOCZ+AGXAYeRs9dn4zUHUdMWUjbQEZD/xC7ywonrSGl3cllZVtwYKAc6wcKqHBjnUY9oRBTEaAbS2DL9xY6tBXOD1g== 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=RpvjKQBEOTrrEFGy3XscM4znZyZdhB2MI4KZHqsSb6c=; b=KOd7sNWS8e3HTQ2d2DtQ1QJc7o3mijFfH3FXoIWhthvVSzuDlDzCwsE5DeV/zsWDPPB7vPT8q4cA7AhjfANWDme5K/dVmQuxtuz95Ti2qoh4/4wb/pKzSPwGZESDE7mB/zupT6h43Ah5x4GS17bDrkzEGAtHC3xljwtVjHmdAfa+1jbWLJAueT/L+3nmGgmm9UlW3JaBZGoCR03wLFgFCTuwnmmDVeZdNRfWoqgfK9jUmnvgH/SyzLMCnXOqbdawteqB2zvZpJzneA4smOWhPG7WOcHSEeGbls8VnzEMpS0XFqUmYzPfTPKtVHpKsy9Q6PlZVRpRhRRioOxeIbYPjA== 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=RpvjKQBEOTrrEFGy3XscM4znZyZdhB2MI4KZHqsSb6c=; b=PdfOfMNUKHNtdorRxVXdTxATKwEaxn4HtyhJmqXVHtKoA/4PKDMfXHhmPSZwm5L7oy4+3rndVgUe6dO7l1NfvAbviGjc4WMBDDXpAK/yt1kCVzfmg9up6MAIcRJMhPIK+YjWmL56AAz427Kt+dqfyt8ZB4ur4cdiivP47plkc+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 CWLP265MB5523.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b9::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.16; Tue, 21 Apr 2026 14:56:28 +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.20.9846.016; Tue, 21 Apr 2026 14:56:28 +0000 From: Gary Guo Date: Tue, 21 Apr 2026 15:56:13 +0100 Subject: [PATCH v2 02/11] rust: io: generalize `Mmio` to arbitrary type Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-2-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=16534; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=faM0ZpteUlJaNJZMTjGbI7mkrrDCMYhjEeLbY0rM2bo=; b=81Koxp9RJC3hxba8mvXB9afBclGGtwdgEORR2NJq9fXTkJLb+ZFGPnT3+B6KfTXXlIvs4Bs+O PGABNSh/1QlDu2wVLUmPExo7yUiXX7d2AHyiU6B+NusmGMXfJ8fpF7f X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5523:EE_ X-MS-Office365-Filtering-Correlation-Id: bac75a47-46e5-4887-4111-08de9fb62a5e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: OF8sboWGzHfUwFY3SIMlSqEGA6LX30q1Ln7K/Bt1cSMIgxTJD2kXsPgX9pmBbQDykFBH4jyk4IB+2Esxo7l2DEtnAeX0DqzPnc48GIq+TZulXbx/49J5+AOtK2cEQjgdq0kKcyGFNOr9lkEiSVRzxW9WDfDyVF/pCEDWzPy2S7beKgOKzCUvINr+Vuj09W0YcjD/9rMpJbxbKiOxmbkWBSW8++UkSaIIrJicUk84X0T+xx9oNKpsSvRxpeD7VjWp5UYnQG6qzawLNCu/Y0ZF/QKBAcYrqaQ7hmKWftMLGrgrmnQZV4ixo4+Xh8m7g9roewyVzMfNkiDDoYEQsvqyRcmwFZwbMt73z183hWpcAL5TaD+FyQy9mBgw5aLRLbsxNLF3FFE1t+ZVJcbeiSYV9WUxSqCGCzIBVMz+AxJ7ICyN9ZduOncFBVcRxyZ0T7x7OwIxqLxE0EsVsfCutoiS1bf5vMmz0JoukkS6YlsTNU5qaynylh/YM7USkBO9b6K+LCwz7we0+FLF7DbGLUaDSIw+FcSFfujQfb3GGFQMXRpkX/pV/cU/HXwZdjZnvDVTZKcQLj8paWTgcLYodUuRqq4nwjpN/2H4Q5k+TAUvqjEDqEPEL2VFSgbg+oVDqnfW2vCD8Smd0INuIdzEu+/jdgtFm1QLFxFS4taK9R9NDuLR1nY9GXI28aSYpQoKh2ge/troeo7+RHibMMTc13Qr/dbt1CEHSqrZsoFUh4mg9Z3eDzUP7mrYcqW8xDQ/VZUJTRlK0dODxN/V+4SCza0lnA== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?UnNkcDljUS9QMGpSSmlLM3ZkcC80Qm5PbnJLZS9JUnIrbmhDUm9YeXhMNFF3?= =?utf-8?B?THVsbDdqNDUzeTdDZjdWVlFEbTJpbUtzNHJwTmZHdUc5eG4rKzNnaXBObDdl?= =?utf-8?B?TjBjOWgzZlAvcVFxcVNQdW1kL3UrNGRhcktpcVhnRmFhTTZmTXZjQkkxVTN6?= =?utf-8?B?Rk9tUlUrNzNJaTN0YkYxSjNDQXBNOGxZVnFSenV4SzBKeVJYeUt2eE1vVCt1?= =?utf-8?B?cVJsNUg2RERIRTErQ1ljZUJSSit1TmdHVlJqUlQ1ZUNVM3hBZnV3aVh4V0tP?= =?utf-8?B?Ny9sQzd1cDQxaC9wbytsV0NISTNFZXRmbXZ5WkpsWWlXWEpWWUxCbCtNZG5I?= =?utf-8?B?OUl5MkhuVm0ya0twcUltazM1Y3NjTDUwZUFQcWxTZmQ2UnpIaVljSVI2SCtH?= =?utf-8?B?R3JJOVRwOHlJemYzOCtnUzlKVzFCRCtxN3BGQlVBdXIvWFFnUTJTSTYydlJy?= =?utf-8?B?QUJKZWRvdWdaaHZhbUxJSDFSZGZaTlhOSjB2QldZZlZkQTBzWXVwdjlNc3lZ?= =?utf-8?B?R1JQT2RLRVhTbkJ3dTJ0MWVsdzdsMHg5NkQwY2R2K29PWjZ5aGx3QVhEOGxF?= =?utf-8?B?Nnk3YjBWYVNqSU4yVWlrSVdPZWlac3NDSFNxbGFHeFovZktPK1VxL2NTQjY5?= =?utf-8?B?bE1reDUzVGZtVzlDRUl6QStDY3B1Q251cm1wRmxFbERiMVN3OGRxbGJZOFZN?= =?utf-8?B?aVhjUDE1bE4vNWFZZmJ2cVhaL2tlR3BwS2JRTm1ieVdqVE14Mkd4OTNxeDda?= =?utf-8?B?VEs3SHl5bkFQYUd5aUlOQTduYWJZZUwwZHcvVVJqemZ0VDFNTm1sQ0dsbDBR?= =?utf-8?B?Z3pGa2ExdXpRK0hoWVVxSjhlRHBuTmVPR2p5MWZLYWVpaDE2ckNEa2RpYndW?= =?utf-8?B?L3Zyc3M3RXE3c2xiODNZWEZLNHVnMHcwSjRQUU1MTWlXTnF3VzdrM2tHZml3?= =?utf-8?B?WUsrb29lTWgxb2RyWnJpMlRLQ3d5bHNKR256d1BmTFJiL0dRNXdhM3NhS29F?= =?utf-8?B?cDJNclBld3EzVkV0NE9LTTR4QWJiZVo0c1JXNnUzT1NPNDVCbm1sckxvYWlU?= =?utf-8?B?Mi82VEh2ODBHL283Wi9sUTI0dEQxTE9rQWdaNXBVQUF4eXRuUUNyeHRaVE93?= =?utf-8?B?S2F4aXlYVmtTaEZZRW9SQVJIUWFqUm9LenhBTlZMdUtPbE94MWgrbVc2c3VM?= =?utf-8?B?bW12OHgxcEpVY2kzWGZETXVUWW05VW9NY1pObFZHQkE0NmlpajBUaHNneWYr?= =?utf-8?B?RCt3Rlh6Sk9TaHF6WjdQMUk3RVhUMFVMMjN1dktuQjkwQ2FCZDF0cngzRE80?= =?utf-8?B?ZVJKQ3VXTTFKYXRucXB3TEVwSUhwWmVucFlUNklYSWM2aXdZWnBEcVk5WjZl?= =?utf-8?B?TStReUloN1FFSzdiWkZlWjJiZ29pdHYzTjRDNW9kTFV0eThEdzNCa3ZFM3o5?= =?utf-8?B?allLMy9ISThWV2dkVzZzdEtZRDV0Y3lxQU5YQXpHTEZlMkM1NmdJcmh6ajV5?= =?utf-8?B?Tms2d2kwZk1Ia09ERGV5OTNza2ZBa1BNa0poT2NzZzk4SXp4V0xwM1F2NTQv?= =?utf-8?B?Wlo1eDYvMnNkYnMxT0JOdUU4NHBOZ2FEdE0zUTBXMTRRTGtoU2JBN1J4UVA5?= =?utf-8?B?WW5uZjFhbWdRYVdiTDBKaXNITkJaWVNHT1p5MTB1cXJZYVRxYXNlSlp4bDgz?= =?utf-8?B?T1hwUXc0WjFRR3dCS1E5b1I2WVdZUk0vNEtSTWQ1aUluSmtmMnFZSDdKMmlE?= =?utf-8?B?MEZSV1pFV3VPcGhVYSsyckdZWWRiY1pqYWNaMENZNHJMS1hhUCtERVBiSWFO?= =?utf-8?B?dFE4NFRoemcveklBMEdrZlZJZ0hNcFdGaWhnWGM0WDBHR3IrUzlyd2kxVVh6?= =?utf-8?B?NEZlTDZUMkVYVTBrem9uQ3VuRDUxaFpCVlVNZGRmczgvQXJSNy81K1MyeXpL?= =?utf-8?B?RlRnL2lzV1c2YkRzb2Z5V0x5WFdlQTdPSXkxekdOSVg2RGJGY0NXUGRhajY2?= =?utf-8?B?M05mTkdCc25ZNzdJanRZYkR6QlZsWWhhL1c1cnlkWUdWTURvSHBNN25vdzVX?= =?utf-8?B?QmNLUkxyWVczMmM0cm1PNVc2OGxMOEw4ME9kRmN6dlU1U0gxaC8venp0Kzhl?= =?utf-8?B?aDE1TGpQUCswaDJTOUphL3VPcnN1d1ZNYXhHbWlDRUFRY0tQOHRXZXpCcjhY?= =?utf-8?B?Y3dFeUR6UVVNdGw1eWxyVHhHanA0MCt2TVRpeDhyNXo1TURuNzZSY2xxVnRZ?= =?utf-8?B?QWJSZTZLdDNoTWZNcldObExXemlFYU1UUTR3NGw5NmU4S3RkeFpPSy9sTVRP?= =?utf-8?B?UmhGS29xdC85Z2ZBZmt6UzV5MXBnQU9zY0ZYYWRNQ1ZiNGFtNlBOQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: bac75a47-46e5-4887-4111-08de9fb62a5e X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:27.7791 (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: wHUMn/98Q1GvCqu2kP+fUEvPgpahshFQlmq47oS/dN0LZIKclqrDs+bN8/YhtC5+9eGsfa9gPQCaquvcsSHbTQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5523 Currently, `io::Mmio` always represent an untyped region of a compile-time known minimum size, which is roughly equivalent to `void __iomem*` (but with bound checks). However, it is useful to also be to represent I/O memory of a specific type, e.g. `u32 __iomem*` or `struct foo __iomem*`. Thus, make `Mmio` generic on arbitrary `T`, where `T` is a sized type, or a DST that implements `KnownSize`. Similar to the `MmioRaw` change, the existing behaviour is preserved in the form of `Mmio>`. This change brings the MMIO closer to the DMA coherent allocation types that we have, which is already typed. To be able to implement `IoKnownSize`, add a `MIN_SIZE` constant to `KnownSize` trait to represent compile-time known minimum size of a specific type. Acked-by: Miguel Ojeda Signed-off-by: Gary Guo Reviewed-by: Andreas Hindborg --- rust/kernel/devres.rs | 2 +- rust/kernel/io.rs | 63 +++++++++++++++++++++++++++---------------= ---- rust/kernel/io/mem.rs | 4 +-- rust/kernel/io/poll.rs | 6 +++-- rust/kernel/io/register.rs | 19 ++++++++------ rust/kernel/pci/io.rs | 2 +- rust/kernel/ptr.rs | 7 ++++++ 7 files changed, 64 insertions(+), 39 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 65a4082122af..3e22c63efb98 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -106,7 +106,7 @@ struct Inner { /// } /// /// impl Deref for IoMem { -/// type Target =3D Mmio; +/// type Target =3D Mmio>; /// /// fn deref(&self) -> &Self::Target { /// // SAFETY: The memory range stored in `self` has been properly= mapped in `Self::new`. diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index d7f2145fa9b9..0b9c97c0a1d7 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -44,6 +44,8 @@ pub struct Region { } =20 impl KnownSize for Region { + const MIN_SIZE: usize =3D SIZE; + #[inline(always)] fn size(p: *const Self) -> usize { (p as *const [u8]).len() @@ -169,7 +171,7 @@ pub fn size(&self) -> usize { /// } /// /// impl Deref for IoMem { -/// type Target =3D Mmio; +/// type Target =3D Mmio>; /// /// fn deref(&self) -> &Self::Target { /// // SAFETY: The memory range stored in `self` has been properly= mapped in `Self::new`. @@ -187,7 +189,7 @@ pub fn size(&self) -> usize { /// # } /// ``` #[repr(transparent)] -pub struct Mmio(MmioRaw>); +pub struct Mmio(MmioRaw); =20 /// Checks whether an access of type `U` at the given `offset` /// is valid within this region. @@ -462,9 +464,10 @@ fn write64(&self, value: u64, offset: usize) /// use kernel::io::{ /// Io, /// Mmio, + /// Region, /// }; /// - /// fn do_reads(io: &Mmio) -> Result { + /// fn do_reads(io: &Mmio) -> Result { /// // 32-bit read from address `0x10`. /// let v: u32 =3D io.try_read(0x10)?; /// @@ -496,9 +499,10 @@ fn try_read(&self, location: L) -> Result /// use kernel::io::{ /// Io, /// Mmio, + /// Region, /// }; /// - /// fn do_writes(io: &Mmio) -> Result { + /// fn do_writes(io: &Mmio) -> Result { /// // 32-bit write of value `1` at address `0x10`. /// io.try_write(0x10, 1u32)?; /// @@ -534,6 +538,7 @@ fn try_write(&self, location: L, value: T) -> Res= ult /// register, /// Io, /// Mmio, + /// Region, /// }; /// /// register! { @@ -549,7 +554,7 @@ fn try_write(&self, location: L, value: T) -> Res= ult /// } /// } /// - /// fn do_write_reg(io: &Mmio) -> Result { + /// fn do_write_reg(io: &Mmio) -> Result { /// /// io.try_write_reg(VERSION::new(1, 0)) /// } @@ -579,9 +584,10 @@ fn try_write_reg(&self, value: V) -> Result /// use kernel::io::{ /// Io, /// Mmio, + /// Region, /// }; /// - /// fn do_update(io: &Mmio<0x1000>) -> Result { + /// fn do_update(io: &Mmio>) -> Result { /// io.try_update(0x10, |v: u32| { /// v + 1 /// }) @@ -616,9 +622,10 @@ fn try_update(&self, location: L, f: F) -> Re= sult /// use kernel::io::{ /// Io, /// Mmio, + /// Region, /// }; /// - /// fn do_reads(io: &Mmio<0x1000>) { + /// fn do_reads(io: &Mmio>) { /// // 32-bit read from address `0x10`. /// let v: u32 =3D io.read(0x10); /// @@ -648,9 +655,10 @@ fn read(&self, location: L) -> T /// use kernel::io::{ /// Io, /// Mmio, + /// Region, /// }; /// - /// fn do_writes(io: &Mmio<0x1000>) { + /// fn do_writes(io: &Mmio>) { /// // 32-bit write of value `1` at address `0x10`. /// io.write(0x10, 1u32); /// @@ -682,6 +690,7 @@ fn write(&self, location: L, value: T) /// register, /// Io, /// Mmio, + /// Region, /// }; /// /// register! { @@ -697,7 +706,7 @@ fn write(&self, location: L, value: T) /// } /// } /// - /// fn do_write_reg(io: &Mmio<0x1000>) { + /// fn do_write_reg(io: &Mmio>) { /// io.write_reg(VERSION::new(1, 0)); /// } /// ``` @@ -726,9 +735,10 @@ fn write_reg(&self, value: V) /// use kernel::io::{ /// Io, /// Mmio, + /// Region, /// }; /// - /// fn do_update(io: &Mmio<0x1000>) { + /// fn do_update(io: &Mmio>) { /// io.update(0x10, |v: u32| { /// v + 1 /// }) @@ -778,7 +788,7 @@ fn io_addr_assert(&self, offset: usize) -> usize { 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 { 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) } @@ -805,7 +815,7 @@ unsafe fn io_write(&self, value: $ty, address: usize) { writeq ); =20 -impl Io for Mmio { +impl Io for Mmio { /// Returns the base address of this mapping. #[inline] fn addr(&self) -> usize { @@ -819,18 +829,18 @@ fn maxsize(&self) -> usize { } } =20 -impl IoKnownSize for Mmio { - const MIN_SIZE: usize =3D SIZE; +impl IoKnownSize for Mmio { + const MIN_SIZE: usize =3D T::MIN_SIZE; } =20 -impl Mmio { +impl Mmio { /// Converts an `MmioRaw` into an `Mmio` instance, providing the acces= sors 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 { + /// `addr.size()`. + pub unsafe fn from_raw(raw: &MmioRaw) -> &Self { // SAFETY: `Mmio` is a transparent wrapper around `MmioRaw`. unsafe { &*core::ptr::from_ref(raw).cast() } } @@ -843,9 +853,9 @@ pub unsafe fn from_raw(raw: &MmioRaw>) -> = &Self { /// /// See [`Mmio::relaxed`] for a usage example. #[repr(transparent)] -pub struct RelaxedMmio(Mmio); +pub struct RelaxedMmio(Mmio); =20 -impl Io for RelaxedMmio { +impl Io for RelaxedMmio { #[inline] fn addr(&self) -> usize { self.0.addr() @@ -857,11 +867,11 @@ fn maxsize(&self) -> usize { } } =20 -impl IoKnownSize for RelaxedMmio { - const MIN_SIZE: usize =3D SIZE; +impl IoKnownSize for RelaxedMmio { + const MIN_SIZE: usize =3D T::MIN_SIZE; } =20 -impl Mmio { +impl Mmio { /// 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 @@ -873,18 +883,19 @@ impl Mmio { /// use kernel::io::{ /// Io, /// Mmio, + /// Region, /// RelaxedMmio, /// }; /// - /// fn do_io(io: &Mmio<0x100>) { + /// fn do_io(io: &Mmio>) { /// // 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. + pub fn relaxed(&self) -> &RelaxedMmio { + // SAFETY: `RelaxedMmio` is `#[repr(transparent)]` over `Mmio`, so= `Mmio` 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 9117d417f99c..a6292f4ebfa4 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -214,7 +214,7 @@ pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinIn= it, Error> + } =20 impl Deref for ExclusiveIoMem { - type Target =3D Mmio; + type Target =3D Mmio>; =20 fn deref(&self) -> &Self::Target { &self.iomem @@ -289,7 +289,7 @@ fn drop(&mut self) { } =20 impl Deref for IoMem { - type Target =3D Mmio; + type Target =3D Mmio>; =20 fn deref(&self) -> &Self::Target { // SAFETY: Safe as by the invariant of `IoMem`. diff --git a/rust/kernel/io/poll.rs b/rust/kernel/io/poll.rs index 75d1b3e8596c..2dce2b24b5ff 100644 --- a/rust/kernel/io/poll.rs +++ b/rust/kernel/io/poll.rs @@ -48,13 +48,14 @@ /// use kernel::io::{ /// Io, /// Mmio, +/// Region, /// 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: &Mmio>) -> Re= sult { /// read_poll_timeout( /// // The `op` closure reads the value of a specific status regis= ter. /// || io.try_read16(0x1000), @@ -135,13 +136,14 @@ pub fn read_poll_timeout( /// use kernel::io::{ /// Io, /// Mmio, +/// Region, /// 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: &Mmio>) -> Re= sult { /// 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 abc49926abfe..1a407fc35edc 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -55,6 +55,7 @@ //! register, //! Io, //! IoLoc, +//! Region, //! }, //! num::Bounded, //! }; @@ -66,7 +67,7 @@ //! # 3:0 minor_revision; //! # } //! # } -//! # fn test(io: &Mmio<0x1000>) { +//! # fn test(io: &Mmio>) { //! # fn obtain_vendor_id() -> u8 { 0xff } //! //! // Read from the register's defined offset (0x100). @@ -441,6 +442,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// io::{ /// register, /// Io, +/// Region, /// }, /// }; /// # use kernel::io::Mmio; @@ -452,7 +454,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: &Mmio<0x1000>) { +/// # fn test(io: &Mmio>) { /// let val =3D io.read(FIXED_REG); /// /// // Write from an already-existing value. @@ -554,6 +556,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// WithBase, /// }, /// Io, +/// Region, /// }, /// }; /// # use kernel::io::Mmio; @@ -581,7 +584,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: Mmio<0x1000>) { +/// # fn test(io: Mmio>) { /// // Read the status of `Cpu0`. /// let cpu0_started =3D io.read(CPU_CTL::of::()); /// @@ -598,7 +601,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test2(io: Mmio<0x1000>) { +/// # fn test2(io: Mmio>) { /// // Start the aliased `CPU0`, leaving its other fields untouched. /// io.update(CPU_CTL_ALIAS::of::(), |r| r.with_alias_start(true)); /// # } @@ -633,6 +636,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// register, /// register::Array, /// Io, +/// Region, /// }, /// }; /// # use kernel::io::Mmio; @@ -648,7 +652,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: &Mmio<0x1000>) +/// # fn test(io: &Mmio>) /// # -> Result<(), Error>{ /// // Read scratch register 0, i.e. I/O address `0x80`. /// let scratch_0 =3D io.read(SCRATCH::at(0)).value(); @@ -719,6 +723,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// WithBase, /// }, /// Io, +/// Region, /// }, /// }; /// # use kernel::io::Mmio; @@ -749,7 +754,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test(io: &Mmio<0x1000>) -> Result<(), Error> { +/// # fn test(io: &Mmio>) -> Result<(), Error> { /// // Read scratch register 0 of CPU0. /// let scratch =3D io.read(CPU_SCRATCH::of::().at(0)); /// @@ -791,7 +796,7 @@ fn into_io_op(self) -> (FixedRegisterLoc, T) { /// } /// } /// -/// # fn test2(io: &Mmio<0x1000>) -> Result<(), Error> { +/// # fn test2(io: &Mmio>) -> 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 0335b5068f69..e048370fb8c1 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -238,7 +238,7 @@ fn drop(&mut self) { } =20 impl Deref for Bar { - type Target =3D Mmio; + type Target =3D Mmio>; =20 fn deref(&self) -> &Self::Target { // SAFETY: By the type invariant of `Self`, the MMIO range in `sel= f.io` is properly mapped. diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs index 3f3e529e9f58..566e68f567a2 100644 --- a/rust/kernel/ptr.rs +++ b/rust/kernel/ptr.rs @@ -235,11 +235,16 @@ 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; + /// 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 core::mem::size_of::(); + #[inline(always)] fn size(_: *const Self) -> usize { size_of::() @@ -247,6 +252,8 @@ fn size(_: *const Self) -> usize { } =20 impl KnownSize for [T] { + const MIN_SIZE: usize =3D 0; + #[inline(always)] fn size(p: *const Self) -> usize { p.len() * size_of::() --=20 2.51.2 From nobody Wed Jun 17 01:38:28 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020082.outbound.protection.outlook.com [52.101.196.82]) (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 B04AF3D9021; Tue, 21 Apr 2026 14:56:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.82 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783397; cv=fail; b=OLLvDmjFNUtOJEGBz2a1CcvL6PNyKCvGk1854qdwvcrVWAjUI6HsPECkSVSoFuY417+4MGAIya6gV3sqlQ3tg9+7IU+KpWvMFuZL8PucKSBI0t8uLKhd2SQWA0pPtVb/aSb81B4wzRWDmHHogTHw5bIdN88Qfy1/DUx/qxG9+gM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783397; c=relaxed/simple; bh=+v90d6nPJJL+5nNeYYRyZ5OswaRENd0OB2njGVD8jPs=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=QD5t00Y0aOuruoAcgbAUzw8u22rErtXZ2Sy39WKCxa1ve0UKcPmQKo47tZwar/1bBqwkA4U+VG5kQ4wleJi1Gf2XDJAiImpsNvKHGENraYFhhf/kzrBzLrl9zKxqhjPGelOqin60D+itESs26k3sLBhqpW7C2LoTLQ4IEBIMFto= 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=tkQEhTUZ; arc=fail smtp.client-ip=52.101.196.82 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="tkQEhTUZ" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=HaGwfNv72mYchzzfVvgspeUAuI2IivVFBPgtTeRZbM8DB7aj8ph6hjLfsavrr4OkaDa7R6dU2bW41BUD1xczxYmplHOuIRopjHRUCZD64DFWeEJPRPOIXQtlU303m9sphuUAiYLstFfq1sy4aMmdnDtMQLuC9ShBCSvrrjSBSzkYlPe1pGck6IqJ1kNXs08bEkGfXMDIk4H9GIy1sWJN9CteXURlHH7J3rVRqDPd6Wj3s9rLYIahEeFaDfA/ziYEHfg0nrBAtMEHcSTj5hcph21jZC2k0gBx6MHIJW/07MvH4RKZbb3ki2j4KO5gToq5HJ/8Iq0mposWb0IA2mVUnA== 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=LMrf3c+zwtgjUAEfo1PPqVecL3lCus38m4GaKEn0YNE=; b=roYH/ekkbH0gAlrjf8/DPh842k2rVGlT3UQRnbKg9wg1bH9/vViiSff1ud08twTma32+/MjHwYsyZ5NTH4VwMNzHXcOicndXmHkFMyKgiynHRghwTztEfbg1NVvadkL88SaAO/mVK0yVShJ7t595kANo5x5mHWFAE58Z7yR/pizjRWiiCFdr3SwRDq/sI4rV3/UhPtYhwH6tWs4HHk8qOaMecODqpNFKOa0pSuq6/O9R8pnWyto3w0KOMXSCe8JI7VyaAOksMfkIe1HQbMDFGEqOSoMioyxe9kx4KdzaZAPMIJzt9CkdnzpGPKzLBmwnAqGABMPe/KxtT+PaBxfUyw== 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=LMrf3c+zwtgjUAEfo1PPqVecL3lCus38m4GaKEn0YNE=; b=tkQEhTUZ61ZhGpzOKQRAkuDB0Ly1iKddFS8/n9jWBEiqDV/sIDG8p5Qk3nzPX/wNGsEqH/4cn2ZVK8rbnS9Hzc3KZE9HItMsKkcXyARfOzwVHUA5mL+v9woWxB0Am7zA5YVXHcsh1IefRb8wpWIiOpXxeTrJCABcerLHtg/mxik= 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 CWLP265MB5523.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b9::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.16; Tue, 21 Apr 2026 14:56:28 +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.20.9846.016; Tue, 21 Apr 2026 14:56:28 +0000 From: Gary Guo Date: Tue, 21 Apr 2026 15:56:14 +0100 Subject: [PATCH v2 03/11] rust: io: use pointer types instead of address Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-3-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=19161; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=+v90d6nPJJL+5nNeYYRyZ5OswaRENd0OB2njGVD8jPs=; b=vDuEVX4OICrx6bQ7VPCc+PjRpdD5QenD1dHrTb3fP1soxlglMrTgxHWFC/Pgx/QR55uYDaPZF 4XiArnKHTapAdTxdAJR9HTNY7MqyWut9f7ldElTDRIiEHGPWx2g0AzF X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5523:EE_ X-MS-Office365-Filtering-Correlation-Id: c3dac4c9-99d0-4c0d-71e0-08de9fb62a9d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: r7i6aAoXO9YKwdyiGKUS/f4fYtuhO8bM7SAcvasLLwGpad3OfhLSydN3XkH/vlSMnrE5/YVdP0RBRNIhkPzDUtb7jZddBuxccDsSWRwmKwOS1pKMFbrb/7AvPmk5w+riAJ9CT36kMeS+Gg3i3bQuQ1+U3ieHFmweX41L0TW8r1RZnjRBw0f3QDi+6YyFr50yuB/6FjMTNtUk52BFuKX+NgcLC4lY387m1XjmHQycM779P2TL6ggfjyhoLxxp+cfU4dDmcZVbmwj1lUVT2gOvW1u2PcBizxFq91ThLJxXhxjaTAOzgo/7ao8pdyx0q2+aAl9QMFS5PbvKzF1ZuM0OpnTq7H0UEG9MI/H9yyYH4lMsKW+u0ldXyz6B1eWPjKZdfZtoePTLqQkKvgy7LNS9hvbaVNDt7hM15IVxqhWpnUigm/GFG9ZHdxvhc4gPzcM8/meKQKUgHtaIN7vgn5XpkNGD2oBa/eJpe8ZEIko+05XTN/UQ/Dq+nu+7DXUlSQdnA+cjKlPe5rrgXxx3wqqNXAcycr7drOTp90Zsk+IFPfw+3olqSRu+PD44sI4WSrneixt9PjvKvP+WoRB+Eh3Qcw2c4dMK7wvSV8+t+nBkvkuAq37osGrfLTsJta/nE+g2eJoE3zgkaP9wVOqqGTdwjZy1SDZtS9Ze/PxD7SBbFlvqJoAb91un5rfIwOvob1TsutPHx/ktJrGILV6adHi+W/u0mcNwPzTW+K7b05jZIy/mKkx3Yk60lRAKtB3HaFPeAZe4ffQh0id2PMjfwB5tdA== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?dkZ6dHhoWFIxY0pNek0xbFR6VVJ1Mlg5N0JXY0dkb2U0Ynh4Zm5QeGlMQk92?= =?utf-8?B?aFBzU0M4YWtJcHQ1NnZ1ZElualJsVTB6MFJFKzd0aHdPN2RiZU83S0Z4U1F6?= =?utf-8?B?Q1FRdXorWTBBRzJTYzJJbjBmSk1VVDRHWWQvNzM1Qzh0VG1uWFBhK2d4b0F2?= =?utf-8?B?RFg5R0lJUWNLL2JXQVJGVkdLd1BOd3NFK1hDUGJFekFXclpCTHkybjZ6NkZS?= =?utf-8?B?U3krUVgwU0JlSld4bjR0eDFTVk5NRlA1aTdCcXp0UFlNTW03RktWendSS0U4?= =?utf-8?B?SFVBd2hYU1cybTNLTGtENkJwZlg2NDZucTgrNytGcWQ0bW0waGFrajVGejd0?= =?utf-8?B?bDE5NnpLS0ZOMkhyYmJJRjlEYjZQSlU3ZHh6c3ExMmN2NGRHbXVsTkQ1SU03?= =?utf-8?B?bllJNDloTDEwTlNsWnFTR05mb2RVaVF6QVNyMU5vUTlzMWwrZDVzV2RMVytB?= =?utf-8?B?NlF2U2w1b01IVDU3eFVFZ1h1SHV4QVlacUcwVyt2TFU0Y1hqQXBZNHk1TVMx?= =?utf-8?B?cHUrb3VyODJjUDFhaEQ4WHRzUHlEeXAvbHJMcXg1bEdCM2RvMHhGQUhaSHQ0?= =?utf-8?B?Vjlnbk1KZkdkOGNaa3JNQmpyTkZVcnFaT3ZNUHJwdEYvazlFNm4vZDY1U0g4?= =?utf-8?B?eFpScmhGQzc4QURNRngzTjFSbHFPdWF3QlB0T0ZDT05yWW0yWTlpZUFxbE5H?= =?utf-8?B?aktwQm1KWjB3UllZRlVwN0RiKzJJeXlXVzV4eUFHclRwc29MMWc1ZmVYTGpO?= =?utf-8?B?dkFEZTI2cU04RDN6ZXdTMGx6dU9yU29ibnFyc0tEdHN6VWhkaDFKWEsydW5K?= =?utf-8?B?dVM0bDhmdGQranhKMGxiOW93ZGp0UTd5OVMyT3d1cHhYZFVMTkFJWG9kQVBx?= =?utf-8?B?aHR1M1d2YTJuRkdpWDhTS00zR21wdEt6YkJXeUJLOHY5cHJtNTkwMisydWdR?= =?utf-8?B?OW1kQkNpSHZObzJuSElqcnBOaUVlcXVmNTdZdEJnQXVvN3pBeXpHMXFqMW8v?= =?utf-8?B?UVRpQUd0TUI2MlVwZWx5bjFWSzZ1TFcrQ056SHhJSXpOeEFPbTNwa05VOHQz?= =?utf-8?B?Vmhtcm8zYksxcGtKdkFYcFB3TUpmZEtPWjJwM0o0TWliWG40b3NzZklPNThN?= =?utf-8?B?aGhISDJaTjgrbzlwaFZvTHJZY3JKWWt4OW9iQ1k2dWVocXhod3Z3Sk9SZ0Zx?= =?utf-8?B?dmU5OFpmdENHY0dsaXh6aTBUTWM1Z09vc21BWjFIUnpUOEJPUHNSc2FNMWtY?= =?utf-8?B?UThsUXlQUDExd044MG5CWXM4NHAvZmEyQ0RyNXBGUHQ3NEJ1T1hzQzJOMUU1?= =?utf-8?B?RDUxclpWR1gzQmlkSmJSdllyNDA5TGt5TVlHZnhCZFIzVzlxOTFpbG13bTZH?= =?utf-8?B?bVhLUExJckZNSW4vWXYrWGtibU96TllETnlzNzRUa2pFU0VXNmVOQ09KYXQv?= =?utf-8?B?T2p1Y0lxYUI2U0V0cnVneTBVYjdPV2g2ZVlaUTdUKysrQ1BRdGFwYWw3TmhZ?= =?utf-8?B?TmFWMll6eDBKMm5EelZ5QWJnU1BTWEg2VEtna3JPT1ZPb0N5SEFMYzJ1d0t0?= =?utf-8?B?Y1dpQXFON2E4eDR0SHJKU2VWSFVRZHdYcGFyVjI0QnlhQStYS1lBWGN6N2dV?= =?utf-8?B?OEZnOWhhUGE0dVF5QnVneHdEL2VwZDVvcGt2TlovUHhIM3gvT29kdXlRZndB?= =?utf-8?B?anJYZG0rOTBBeW4xZU8xTVJyaTdqZWp2K0R4RDRNNi9mdWdPLzYyU0VmSURz?= =?utf-8?B?aStxQ1lhK2krdEhjRkNYVWZ6ZS9mY2d0ZG9DZjJSUkhNOTZLcXNUK2ZVMGxp?= =?utf-8?B?ZEUzRjV5OFVBL0wyTmNUaWtyMTJBeGlyeXYzeXg0OFhVVTViK29rNjJ3QkxD?= =?utf-8?B?Z0MxSjdGOWcyRS9obmtHVVBnZ3B0NytmdVJvYThOaFNyU0FqTFJ0VThUUjNU?= =?utf-8?B?WXFCekNvRk82cWc3UnpmUUlKL0lad0FiVWVjbXlRSjc3OEZkbUVHczhwN040?= =?utf-8?B?cHhFRzY2TUZ0azVtOTlFSklnMTlmMm4wbGJnZElkaE9VVFkwdnJaeS9ZSXRh?= =?utf-8?B?Y0NJOHlQUUxHb2I0S09LMjJkUDdURlJmQ0s2R0k3MmpVcTNpNFQvdUlqMklF?= =?utf-8?B?ZjVjaitHc2ZTVHg1NlBXMmVrTXo0N3ZoVjBRUTVMSTlyRTJZOVE4SjlFL2NR?= =?utf-8?B?d0J5M3lHeGdKSzBNQk9XWFlyalFxTE1EcDJRa1pNTW84VG1GVnpCVlVPYW1k?= =?utf-8?B?S2g4cEgrbEVBY3VyK2tIVm9oa0Z6SSt4UjBTQ2dkWGtPT2E3RTN3SjBnNkdD?= =?utf-8?B?aEV2cVNxT3Ewb3dwL25ncEl2SmpJSE8vaUhjSjlyakM3MWdyRllsQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: c3dac4c9-99d0-4c0d-71e0-08de9fb62a9d X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:28.1880 (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: hZcMwBZCgR2Ml0FPY5vTc3uhkoRdzqcFg7l8CbxSViYmnI7T4kOGC1IiXxEEiuDjjJN0fGDCE4mx6YAROvplBA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5523 This carries the size information with the pointer type and metadata, makes it possible to use I/O projections and paves the way for IO view types. With this change, minimum size information becomes available through types; so `KnownSize::MIN_SIZE` can be used and `IoKnownSize` trait is no longer necessary. The trait is kept for compatibility and can be removed when users stop using it for bounds. PCI config space uses only offsets and not pointers like MMIO; for this null pointers (with proper size metadata) is used. This is okay as I/O trait impl and I/O projections can operate on invalid pointers, and for PCI config space we will only use address info and ignore the provenance. Signed-off-by: Gary Guo Reviewed-by: Andreas Hindborg --- rust/kernel/devres.rs | 2 +- rust/kernel/io.rs | 123 +++++++++++++++++++++-------------------------= ---- rust/kernel/io/mem.rs | 2 +- rust/kernel/pci/io.rs | 74 ++++++++++++++++++------------ 4 files changed, 99 insertions(+), 102 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 3e22c63efb98..ea86e9c62cdf 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -101,7 +101,7 @@ struct Inner { /// 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); }; +/// unsafe { bindings::iounmap(self.0.as_ptr().cast()); }; /// } /// } /// diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 0b9c97c0a1d7..1682f2a0d20d 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -105,8 +105,8 @@ pub fn new_region(addr: usize, size: usize) -> Result { impl MmioRaw { /// Returns the base address of the MMIO region. #[inline] - pub fn addr(&self) -> usize { - self.addr.addr() + pub fn as_ptr(&self) -> *mut T { + self.addr } =20 /// Returns the size of the MMIO region. @@ -166,7 +166,7 @@ pub fn size(&self) -> usize { /// 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); }; +/// unsafe { bindings::iounmap(self.0.as_ptr().cast()); }; /// } /// } /// @@ -217,14 +217,14 @@ pub trait IoCapable { /// # Safety /// /// The range `[address..address + size_of::()]` must be within the= bounds of `Self`. - unsafe fn io_read(&self, address: usize) -> T; + unsafe fn io_read(&self, address: *mut T) -> 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`. - unsafe fn io_write(&self, value: T, address: usize); + unsafe fn io_write(&self, value: T, address: *mut T); } =20 /// Describes a given I/O location: its offset, width, and type to convert= the raw value from and @@ -291,23 +291,35 @@ 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 { - /// Returns the base address of this mapping. - fn addr(&self) -> usize; + /// Type of this I/O region. For untyped I/O regions, [`Region`] type = can be used. + type Type: ?Sized + KnownSize; + + /// Returns the base pointer of this mapping. + /// + /// This is a pointer to capture metadata. The specific meaning of the= pointer depends on + /// I/O backend and is not necessarily valid. + fn as_ptr(&self) -> *mut Self::Type; + + /// 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) -> *mut U { + build_assert!(offset_valid::(offset, Self::Type::MIN_SIZE)); =20 - /// Returns the maximum size of this mapping. - fn maxsize(&self) -> usize; + self.as_ptr().wrapping_byte_add(offset).cast() + } =20 /// Returns the absolute I/O address for a given `offset`, /// performing runtime bound checks. #[inline] - fn io_addr(&self, offset: usize) -> Result { - if !offset_valid::(offset, self.maxsize()) { + fn io_addr(&self, offset: usize) -> Result<*mut U> { + let ptr =3D self.as_ptr(); + if !offset_valid::(offset, Self::Type::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) + Ok(ptr.wrapping_byte_add(offset).cast()) } =20 /// Fallible 8-bit read with runtime bounds check. @@ -386,7 +398,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) } @@ -395,7 +407,7 @@ fn read8(&self, offset: usize) -> u8 #[inline(always)] fn read16(&self, offset: usize) -> u16 where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.read(offset) } @@ -404,7 +416,7 @@ fn read16(&self, offset: usize) -> u16 #[inline(always)] fn read32(&self, offset: usize) -> u32 where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.read(offset) } @@ -413,7 +425,7 @@ fn read32(&self, offset: usize) -> u32 #[inline(always)] fn read64(&self, offset: usize) -> u64 where - Self: IoKnownSize + IoCapable, + Self: IoCapable, { self.read(offset) } @@ -422,7 +434,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) } @@ -431,7 +443,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) } @@ -440,7 +452,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) } @@ -449,7 +461,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) } @@ -637,7 +649,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 @@ -670,7 +682,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(); @@ -715,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 @@ -748,7 +760,7 @@ fn write_reg(&self, value: V) fn update(&self, location: L, f: F) where L: IoLoc, - Self: IoKnownSize + IoCapable + Sized, + Self: IoCapable, F: FnOnce(T) -> T, { let address =3D self.io_addr_assert::(location.offset()= ); @@ -762,41 +774,25 @@ 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)); +// For compatibility only. +#[doc(hidden)] +pub trait IoKnownSize: Io {} =20 - self.addr() + offset - } -} +impl IoKnownSize for T {} =20 /// 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 { - unsafe fn io_read(&self, address: usize) -> $ty { + unsafe fn io_read(&self, address: *mut $ty) -> $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: *mut $ty) { // SAFETY: By the trait invariant `address` is a valid add= ress for MMIO operations. - unsafe { bindings::$write_fn(value, address as *mut c_void= ) } + unsafe { bindings::$write_fn(value, address.cast()) } } } }; @@ -816,23 +812,15 @@ unsafe fn io_write(&self, value: $ty, address: usize)= { ); =20 impl Io for Mmio { - /// Returns the base address of this mapping. - #[inline] - fn addr(&self) -> usize { - self.0.addr() - } + type Type =3D T; =20 - /// Returns the maximum size of this mapping. + /// Returns the base address of this mapping. #[inline] - fn maxsize(&self) -> usize { - self.0.size() + fn as_ptr(&self) -> *mut T { + self.0.as_ptr() } } =20 -impl IoKnownSize for Mmio { - const MIN_SIZE: usize =3D T::MIN_SIZE; -} - impl Mmio { /// Converts an `MmioRaw` into an `Mmio` instance, providing the acces= sors to the MMIO mapping. /// @@ -856,21 +844,14 @@ pub unsafe fn from_raw(raw: &MmioRaw) -> &Self { pub struct RelaxedMmio(Mmio); =20 impl Io for RelaxedMmio { - #[inline] - fn addr(&self) -> usize { - self.0.addr() - } + type Type =3D T; =20 #[inline] - fn maxsize(&self) -> usize { - self.0.maxsize() + fn as_ptr(&self) -> *mut T { + self.0.as_ptr() } } =20 -impl IoKnownSize for RelaxedMmio { - const MIN_SIZE: usize =3D T::MIN_SIZE; -} - impl Mmio { /// Returns a [`RelaxedMmio`] reference that performs relaxed I/O oper= ations. /// diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index a6292f4ebfa4..f87a29f90e79 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -284,7 +284,7 @@ pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinIn= it, Error> + impl Drop for IoMem { fn drop(&mut self) { // SAFETY: Safe as by the invariant of `Io`. - unsafe { bindings::iounmap(self.io.addr() as *mut c_void) } + unsafe { bindings::iounmap(self.io.as_ptr().cast()) } } } =20 diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index e048370fb8c1..63c35eaab6c3 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -10,11 +10,11 @@ io::{ Io, IoCapable, - IoKnownSize, Mmio, MmioRaw, // }, prelude::*, + ptr::KnownSize, sync::aref::ARef, // }; use core::{ @@ -60,14 +60,37 @@ pub const fn into_raw(self) -> usize { pub trait ConfigSpaceKind { /// The size of this configuration space in bytes. const SIZE: usize; + + /// Region type for this kind of config space. This should be [`crate:= :io::Region`]. + type Region: ?Sized + KnownSize; + + /// Obtain pointer with actual size information. + fn null_ptr_from_size(size: ConfigSpaceSize) -> *mut Self::Region; } =20 impl ConfigSpaceKind for Normal { const SIZE: usize =3D 256; + + type Region =3D crate::io::Region<256>; + + #[inline] + fn null_ptr_from_size(size: ConfigSpaceSize) -> *mut Self::Region { + core::ptr::slice_from_raw_parts_mut(core::ptr::null_mut::(), s= ize.into_raw()) + as *mut Self::Region + } } =20 impl ConfigSpaceKind for Extended { const SIZE: usize =3D 4096; + + type Region =3D crate::io::Region<4096>; + + #[inline] + fn null_ptr_from_size(_: ConfigSpaceSize) -> *mut Self::Region { + // Small optimization. For a extended config space, we already kno= w that the size + // is 4096. + core::ptr::slice_from_raw_parts_mut(core::ptr::null_mut::(), 4= 096) as *mut Self::Region + } } =20 /// The PCI configuration space of a device. @@ -87,28 +110,28 @@ pub struct ConfigSpace<'a, S: ConfigSpaceKind =3D Exte= nded> { 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>= { - unsafe fn io_read(&self, address: usize) -> $ty { + unsafe fn io_read(&self, address: *mut $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 address.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 `self.pdev` is a valid ad= dress. + let _ =3D unsafe { bindings::$read_fn(self.pdev.as_raw(), = addr, &mut val) }; val } =20 - unsafe fn io_write(&self, value: $ty, address: usize) { + unsafe fn io_write(&self, value: $ty, address: *mut $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 address.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 `self.pdev` is a valid ad= dress. + let _ =3D unsafe { bindings::$write_fn(self.pdev.as_raw(),= addr, value) }; } } }; @@ -120,23 +143,15 @@ unsafe fn io_write(&self, value: $ty, address: usize)= { impl_config_space_io_capable!(u32, pci_read_config_dword, pci_write_config= _dword); =20 impl<'a, S: ConfigSpaceKind> Io for ConfigSpace<'a, S> { - /// Returns the base address of the I/O region. It is always 0 for con= figuration space. - #[inline] - fn addr(&self) -> usize { - 0 - } + type Type =3D S::Region; =20 - /// Returns the maximum size of the configuration space. + /// Returns the base address of the I/O region. It is always 0 for con= figuration space. #[inline] - fn maxsize(&self) -> usize { - self.pdev.cfg_size().into_raw() + fn as_ptr(&self) -> *mut Self::Type { + S::null_ptr_from_size(self.pdev.cfg_size()) } } =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 @@ -219,7 +234,7 @@ unsafe fn do_release(pdev: &Device, ioptr: usize, num: = i32) { =20 fn release(&self) { // SAFETY: The safety requirements are guaranteed by the type inva= riant of `self.pdev`. - unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) }; + unsafe { Self::do_release(&self.pdev, self.io.as_ptr().addr(), sel= f.num) }; } } =20 @@ -267,6 +282,7 @@ pub fn iomap_region<'a>( } =20 /// Returns the size of configuration space. + #[inline] pub fn cfg_size(&self) -> ConfigSpaceSize { // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. let size =3D unsafe { (*self.as_raw()).cfg_size }; --=20 2.51.2 From nobody Wed Jun 17 01:38:28 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020082.outbound.protection.outlook.com [52.101.196.82]) (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 531943DA5D8; Tue, 21 Apr 2026 14:56:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.82 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783400; cv=fail; b=LvrrcJT8JL49c6rQonsZoNR3US2R1P5Z3isoMpxZL9zNdf+WiQ5uY1aMwDUySI8prodck809ZDRFdPzBNEFU5J3d0+GhteVQhYNg/h73GtPn3NXewfly6K5lrkpe5oUpz/Hb7TdoB4J5bVThn8G80Yj+xRDlMjKwEJ7qhh3T1gs= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783400; c=relaxed/simple; bh=uAP2XusktosMg6Sijfjq1oOzEOUFYQ++m7dbhH46Bzc=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=PJRj3wDhRihCgCqdWBYY1fWTx5Sh7p1+af95VMXW5mfpG+esibC9wXFtUoNFNAuYvOUkbiX01j0VC3WWIVM+xA2AUnptqdsr+EOgpMDS16AheSwSzw5rm+eM6d+qws/piqbplUDIcIlmmDYlLUZAL+ZPIKlLWczKbhQdzKVEZlg= 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=vQPuSpRS; arc=fail smtp.client-ip=52.101.196.82 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="vQPuSpRS" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=I+r1DNLQt5Vbi02/Gn+32d443GmuEvCo7/c0R/jXZygbSIVOJp6iU55MP1ojkt51AFy7mRSI0U6q4P7/JXPOjW0EEl03Lh6Km7mrwMpfNh8Y8TouRJfzc5wSbhjb0ealklVJDAWCe1pgF6QapDMI0sRr/VqCLJCN5TE8eYzwwpsv83Dynp3mw0QM22wXEWRbo4+YiXKxjUIRRtBuAb8A9ntOP+vqxtOycyGIDtR31Hx2ORQu6fSHX1uqflAkDBwKXDhTCUIb+qLkf52kJ2NPhUAbk5tyKHBRBW6yJMdy6PseQ/ksbqYvwnxuxgPNSZ+LPNCFcC1KCRgUrnxIA3i/zg== 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=9MS5uMU0rcBULjS2MOKbxruodp5TKYeruE7ZCaGTkKU=; b=pukbv0okIDjzX5MTHQ8+/v5yWnHTOOjmWLSDLuzZ/ladF5ngco2M37fBGAfIQvYSKZNMV9Z8hHhDSRaaQgyE9zM+wIOgRu0+TVomWy5W+dsUDcvTQ6LoAHTDTz0sKBgXDYDTML6c6aV9JL+7w7coFrARmo3k8riFO4t7qKKMKchmuzq9W2poP6z0MfB23rYjlCHYW5wo+GczK3Dj+c7XpuwSzrzIN469Ssjl0Y5GyuYp2+jZ7o4JEiiCjHG1oq+xhg1/8eAnznUALW5s2WbPwUJOIC9d9NOdpZSSZYDWbVaAq1IUrxm11U/FR0cGgxew6TRj9G7gcFOq1Ci/IEnwNw== 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=9MS5uMU0rcBULjS2MOKbxruodp5TKYeruE7ZCaGTkKU=; b=vQPuSpRS/CB9bjpsmDQecdvBxt6r2wJuPMjY8m2iUu6UFdgIzOnGAwDLT5NoSio81BZ2pNLoosEhB9OFY/B8kU+4l5Ov6P6uK9cLCx7QhZi7y/rI4K/rEjtY0PfefTUkt+LoBReokZbRjDf6lU+V7a/eGFCdWfu2zxZo0AtPoLs= 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 CWLP265MB5523.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b9::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.16; Tue, 21 Apr 2026 14:56:29 +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.20.9846.016; Tue, 21 Apr 2026 14:56:28 +0000 From: Gary Guo Date: Tue, 21 Apr 2026 15:56:15 +0100 Subject: [PATCH v2 04/11] rust: io: add missing safety requirement in `IoCapable` methods Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-4-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=1265; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=uAP2XusktosMg6Sijfjq1oOzEOUFYQ++m7dbhH46Bzc=; b=T/DxIPKbR50JPwauKc5lcbKe8Mc0kJXvMEuqXWE5g5y+xfPhMfFcBFVAWT1k6UbmxYseMW83l Vqf7hzomrTsByj538hlbVQpY6MU0PDoCPP/DtuIXFbeRxCMabFiZje2 X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5523:EE_ X-MS-Office365-Filtering-Correlation-Id: 5da74dcf-26b1-4093-b139-08de9fb62adc X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: KDhs8dUvvw00usTUzEvc6xHCvg4Yn2nqTmek4iHFXuODVMuzLdiVHN/KduYg89nfuMN5axXURzFxFIa+k6JF8cTFHLnz0wfqReGmfY9D785tSljz0uDpSbgpkzsaoSlLQ3S0KxuXQ375Dnq/qRWBJGu2Rh3SV/DKIKW4YVWSF0GwH5QcDLu1K0nH8/lfc3F81FyyW5+zgHYV7sy1Ag0+PoBrRomT78DYovQdq7Q+Du3qhw26sFnaboUzRQ3kC8j7G5x8HZaUBB4J13/2VTYo4YRa24ci4dBGcAmjNwUN4syByJQpzm9UM5dlVCIG8Hw8E792pzJ/H2fJwXzqZ4ug3wcHJ4RiLOITeMZVgt/yal1+yITyR0to2cl49fMCUkchK4ZiiMqMSilD8iIlHsN2THz9hxAdMnS7yuazvH2V0DKiuFDHLPGKp4kOeTeWfoCwFBavsKd3/HkkMBaAGULrL1JZNp0Ecg3x1jhR6YcPjjq5QIwCanZYsNCZbCjkKu8kNIdcOuaP7vK78vB7vTxtXCqFsrcRUGooh4Pz0HbUs9B6BidB9UDziQEZ3Db2gAQAG+GuL+zFvmCuwMY+lCmbhnH7kJar9mr5S9+WxBsGiFT/6cp+i+m7iWpn/jpAz6nidJHzhzPb9tqLpWt/jfmIPIBAe/QVOGVzh1DAn79yMI9fcVKuu81POh/ChHupV6iGeRzXyUWjnJG2fyGpHy1s6MA2YuRR7BgF0TS+btKjlMxCPkVkVw+2ScfHqKpSxXy44z6Z97woWrylz0TQxiZVog== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?eTdVTGJmTFJ6SGg1ZUY1dHBTa0FabWFObnJpSExUalhUaXVLVCtYM0d0bUhV?= =?utf-8?B?SkgyS21HVUI1ZFZVZEFRZ0xZNzYvRDQ5MElvK3FqUzU0NmYwSy96UktuRGZ3?= =?utf-8?B?SjRITjlYK24yNmdtY3VINHFPSmhYVXduMFBzOWhaejFqQUxBTmh1MUZtRndt?= =?utf-8?B?ZXYxRWhXZXNjaVozTy9GSU1RTnRING94OENXL2x1RTNEZk5sOE9PRGduSWQ2?= =?utf-8?B?a3V4QVhLZWtOaFRUZnBqQ3FZa1RIS2oxTXF2Z0RiNEJVa1E2NlNDN3Rkdjg5?= =?utf-8?B?K2tZcnoxeHh1czVXMU5Tckdhd0liZmIraU13REp5K2NvbHQxWDBlQVVpcGlN?= =?utf-8?B?cWZaakxObVZIeUJMSERzWEZoVkJYT0lpMEF3ek9pd0NOOWVuMmdRcWJzTDFG?= =?utf-8?B?RVFKcUN5QlFiZmVFMTVEK2hNV3RkaWE2bUJnOEZpUVVKYkVRWFZuVTc3a20z?= =?utf-8?B?YlhJdUJoa0R2bHc4MFVCTWg0dlhNRERkSlZMSFlaNWYybDEzcDJaNzNKS1l1?= =?utf-8?B?cmZ1MEYrTkFPUEk5ZUpUYkNsV2tRcjRCcFZRdEN2b1VvMkxtNDNCSVJmMzdq?= =?utf-8?B?dmxBaGl3SWxWdG5NVFNQdmd3aUxyMkhkb01TaFpQZndaYWNjRFM3N1Rwclh3?= =?utf-8?B?TVorNGZmTU5lTHNHK28wMnQzamVmT3lyQkZFcUljS0tGNHNNZjg5WE4wUlNh?= =?utf-8?B?c0lCRnFvcDF6UFdCZnF4aDNBT2N6UXk3MThwbGk1N3BFbGo1ZS9vRXNNU29v?= =?utf-8?B?ZHNNRHlsV1FVVVZkcWZRYjI0WEZ4bHhwRUdjempFZGYybGlZeWlJRmZxN0tC?= =?utf-8?B?VWVvbk1na2hBMUFXeVNUR3AxVTZvUFl6S3VYcFJvaEIxWVpNYTNEL0FCZWdz?= =?utf-8?B?WjdqaHZqbkhEVG5kQmErVjJmQjRMWjJ0Vm84VERhdENPRU53VmIzWG0wQ2FE?= =?utf-8?B?SlkvY1h3L2FHZFZYV0Y3TjlhazVZdDRGN01LMS9CT3FkNlhMSUptdkdEVmRm?= =?utf-8?B?bzdmZUhzQzA4WDNpdXhqY0ZwbWNXV3RYNTJwU29Kc1FIODYxd3FlOWpYOW8x?= =?utf-8?B?RXZhNmZMeDh5ZG5Hb213aVErdDZwaUxjWUZZQWhCWjBmQndSanpXZS84Ui9V?= =?utf-8?B?ZnVoNzZnT3JUZitVRStOSzJXOWlIcVJBQXZQajhJODFzUFVGamQwa3NJRzlL?= =?utf-8?B?cWRSQTJMQnhES2NJQjhsNUVKMWJXeUR4b1JPM2VNRllNWUFNNEtXbms2RmNN?= =?utf-8?B?TVMwdWRCcG9oZEtKdkVIWHgvSkhIczNDek8vcDR1RFErVTNDTm5Balk0Tk9O?= =?utf-8?B?dXJidmZZbkZoYWFiUHJhOC9OZmtTUEswNng3SnFldUFNMFp5Q1B1alJ1NlJG?= =?utf-8?B?TGRTS3FiNUVZOEVwV2p6ZmRTbTliMzhPSGsycGtHa3JTMlUvNUtFcGlaZmNT?= =?utf-8?B?TUJ1eDBUcld1VDVXMm5JM2U0dzdEN3NlclhOeVYxQTNGbm5MQ1lQWDVIUjEv?= =?utf-8?B?QkY0RDVkUE1rQWcvd2hUSnlISFFqWUJFVEtONkRCK1EraFVNM2dRaHFUWHJO?= =?utf-8?B?Y2xyWXlaWSs0MzdQc3JFRGxyc0pZT1d0MTZJa2hLNmpxSHIreGMxbXl3WXY3?= =?utf-8?B?eDZZbHZEU0ZBT21QYmFENkp6dk5oM0JIU0ovazRjRXJXL3ZWSnVxYVliM2N0?= =?utf-8?B?YURrSVVpa0R5TEhQcjFFV0tlR3k4aWJCODY5Um40MzBSZDd6dW9TUW1YNDB2?= =?utf-8?B?RGpkenBDVGRCRnQ1LzREa2JPZmQ0YU1xTXNWUmtOR093amFNb1ZYaG5EaU02?= =?utf-8?B?V0RDMkk3bnV5RlVVUThDa2E0eEYxaTNVUGxlL3FJODJKTkxzYjZobmw2Wk9r?= =?utf-8?B?cjZEZEtGOThvbURQZ1dWWHZSajk5U3VtWXZ0N2Y5cmdhOTJtaEowSGRSd0Zq?= =?utf-8?B?dTU5QWhiaXpMNGEyNzM0SU03K00xWUFwSUdMY01saUE0QmgreGxMSWppNHQr?= =?utf-8?B?NUJ4blNHckt6aHYwamRYdFN5bkVEaGtQQzNzcWxnSk5hUDlORVZVWWNpMFNh?= =?utf-8?B?aWFTRXVQRzZLWHh4c2RralZYdnEzRXMrdG1CT1pIaDZJQ29vSWN2ck5Vby92?= =?utf-8?B?SUJhVE1aL25HcXRlY1FwWUxucXkyWWpHemtZY2NGdFhCR0RsQWlnaWIydHhY?= =?utf-8?B?cW9uRUpxYWNNRWlINDRDRU1iWGp5bW9nMXdOT2NiSVJ4THhJZkRxS25SSzdJ?= =?utf-8?B?cGYyeDVqNkR3Zzl0SnN0dkMwMFJYYmxLLy82OFJ2NGVmMWFabnJqRXBUSmk3?= =?utf-8?B?bWV0Sm9VNHNEZHhjVFZBT3RFaUVuK3NiOUxrNVVHVzcxRkM2RGVQZz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 5da74dcf-26b1-4093-b139-08de9fb62adc X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:28.6164 (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: gLXfx8rZGrWT0EWSYtOynl1DHW37qRUxvgjE/i46PJW8T4le/tpK2mJrushn6xQM+xjyhIFXWjllTkEMREJReg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5523 The current safety comment on `io_read`/`io_write` does not cover the topic about alignment, although this is guaranteed by checks in `Io`. Add it so it can be relied on by implementor of `IoCapable`. Signed-off-by: Gary Guo --- rust/kernel/io.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 1682f2a0d20d..c6d30c5b4e10 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -216,14 +216,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: *mut T) -> 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: *mut T); } =20 --=20 2.51.2 From nobody Wed Jun 17 01:38:28 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020131.outbound.protection.outlook.com [52.101.196.131]) (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 1181F3D9038; Tue, 21 Apr 2026 14:56:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.131 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783395; cv=fail; b=RPQLBwhMAZxc9jEg6kBxbyN2U0Mp2nhuP3BxiNtHKSm/3S6R9iaFBmeBJwqbF+xpN2jq7oL56qAUa8tWaGb5Yy5wnrtGH8yWIRDLleYCGV2majWp9ME8kj5rOLHXFbUNSvm6WD+/S+ZEPCy6PeQEGQPnM1M+qkMoeZGQ1OWWFf8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783395; c=relaxed/simple; bh=5GVZfqmlRD7YS7IuSASRsDrAHqXip3Elc7FIgJl4J90=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=uvE+8RaZ6eI76Hr9Mzad/kFYK1OvNlwqXuKKOe7u1jxoxQ6zeZ7QVqKt0vnvh1SUViY5rydPbnc5FC4H6ETVW3uFxqFvTP1EW2bEE/gSa9ZjK9w4/lEuBGOREr5TSFzZfoMBhxcnAaYa+LirWrFHTUFhWVrFkeAckVc16tAwE6A= 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=cm+4JCk3; arc=fail smtp.client-ip=52.101.196.131 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="cm+4JCk3" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=S1JnXNn4Zb26InXVpjl6gmdj4bUlVRvWJieswDgDL03Bp3gc61Qi/MGW/fgKc6wGd5tBwZP6tmnWCMJu+vFbL+ddc2bHrCvLG6fUCpp5VLZBbHz6qgX4VIB3PbwfiUrmw166gTRp2HoGMMzRHXTr7zXxgTpjI0HdzVNE0aNNBYfGJ0eXefJHO5jz+nBTpOEfhxdw/c2J/Pv8UQGD1FqaOAHvV90DyysydBLFmJTBJ+3MRllDu3M4D9iXaGHr0ecbJzExN3PY0MEqZdlYPALLtggKSwahLuXd0wMNlf6V+V9zNEzupvLySQ0DYNaum0tFFytfQ+TkaDyNLkbsr0F3/A== 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=gz3InflAKtslVQJSJgHeMm1kKTjdd/kLAIC9qXKn59Q=; b=h8BP9FqLKnS33bacO6FUK3uryFXX/cTLkv3g1myeFfRCscTURDnbH+ERuzKZc8bRxf9ngMKwLIPWWg/EyNKegN/E+AP83YQrywVJVUHijUYZiqRRLhDZiwsqkkhogJkooqyHEs9ng7f2DlDwQ9GrS4R7ldKHlpUh0F18VcTRvEoLyP7McufxP2016QEXXieNxj6lA0z1Ks499lcrzobH0FJwfEpMv5EOLn03G+PggWcj7LDmoG8PB/bJudK/hXzDc1ltAKofNyvFhohqzGNXfMCHmG2u6/B/A2nSlwkAodJ7yS0b0XlOyKe7mUTw1JkJAEZz4ENW+7hsERsrag9kwA== 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=gz3InflAKtslVQJSJgHeMm1kKTjdd/kLAIC9qXKn59Q=; b=cm+4JCk3ICMruZutIeOuFVyPP3lgT6qN4jJGEwjpooGYqVBbloLK0IwK1YBygtpTsJWIejCvd5/HXksoz8IL5iXDl9hoqGQFrgNh5a214o/qRNr2mdwYW3hWgKZ8bczytII6y1cbtkW0P+0dc3QmZogYxSHZUtXeAoe5JKE1AO0= 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 CWLP265MB5674.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b0::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.16; Tue, 21 Apr 2026 14:56:29 +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.20.9846.016; Tue, 21 Apr 2026 14:56:29 +0000 From: Gary Guo Date: Tue, 21 Apr 2026 15:56:16 +0100 Subject: [PATCH v2 05/11] rust: io: restrict untyped IO access and `register!` to `Region` Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-5-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=13259; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=5GVZfqmlRD7YS7IuSASRsDrAHqXip3Elc7FIgJl4J90=; b=c1qQ5DpiFXu6Q0zRPZm7320fqpB78rfHQksb0sudcivMAAKQYhzpxwNBIUibr1/TiYsVppY+p 7AbPH/XqylgBDkvynB8TgT9tMoNc/xeftqQZz0KLpoay1KVl9dinsf4 X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5674:EE_ X-MS-Office365-Filtering-Correlation-Id: 8a6122e1-0478-49c1-b797-08de9fb62b1e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003|18096099003; X-Microsoft-Antispam-Message-Info: w9F7UZYmeXl2Nk4FbIOOuMmyidCSMmgu6s8FekySQxwyaQ6ELAipScnds2x+DwaHZqXtMr/1dcOh+wujm9wZu49HsOAipnwTavvgFJoNLxpExu9FQwJeaOBOBYQsHeOR2a9Br5ig7WzBgblqAYBfkmSwxpqwEocJ6JlN2C1Jmpoh56fKWse/gaaqy1e/GU06bzY5ii4+MVTTZvi9wYNfLXY3LrVjR/T0SjfdDpoj89ee1PqxQyLUT2MON/QczapouZ1agggk0ANcFscc3A24OORaw/nC6OAzSe3w6+vbzlBtmzORo5q9a6Nar+Ffv12vMbEfUNbRFb5iGNm/eIoEtcs3R+8vdtdwbpe0f7utuz2ya7taPX3G5QdPB9W/K0kUOnMUwpCHEcQ2WjtE8W6+f9O07BvPZXEuKNLG4JKHqjZYL/+FwDedWUVai1+tFgQPqo9vk9sy5zo/tQ3M4+iPmL2MnQuNTyWPhAkx2/1vD/T8sI41AVfNtwM93csiRCEAkix43j2bk7jJJatEvgBMez+ln2CCUZSjSX8V8kabICdA5PuLHOA8LQJFrqq22suOvjOgMw6cLisllYpmoynEiJilXwgMR/+f6PXR0rjuq2R7GqNMm4Zje018TdnymwPmvEchooVfA68Z/2wjIYvrJcJlNN4AiUltn1RTsnv7DlUdaMhWAohyTnRsDAknLag52saWmzY+PkDSNyQKzd4wFROksSKIQDznzQyhQ64j90GKiH3hIjkmfDcIldEZFNRcvSQZ6iH8LND9r2clqzUueQ== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003)(18096099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZmI1ZURDdU5UUjU4ZW5ZU2h1M1ZuOEpHOUtoL1lBTUk4NlhrbFU1d0ZRTFFa?= =?utf-8?B?M2FodE00TWJqR3BzSUQ4ZDlPSWRZUDlhTWU5ZzhrUy9nV1ZWMHhtREl3M256?= =?utf-8?B?M2VHNllITjBZMjR5RDkzcEk1MnpKRElySFoycWEwV0JUVkZDNlpCRlhzYjJu?= =?utf-8?B?THhRM0NsNVAyMXlSRzNaWkwzL0w1eUMxNGdmVUI2aFBhUkRGcXJSQUJqekRD?= =?utf-8?B?dWNVNHlOMzkxbUFKZVBoREFGeVRLcGI1SHJRR2hWZlI5NGJQQU1wRnJzYUM4?= =?utf-8?B?UWl0NzVOZE95RWh3OHoyYXRDZW9OOWlTQ0g5eStVNWoxM1J3ekw2Zmo5NjJ3?= =?utf-8?B?UDh0dE9TNDF6cUVBMVpWS29temxaN1RyRFNhd1djTTFOVkd3TzlzTTVacEp2?= =?utf-8?B?RU5BdE1kSFFYMk1UNS80RThsODlPNnZ4SldPNVZZQUd4QUpqMDNKQi9NYmVC?= =?utf-8?B?NDRwZCtJd1BZbnhld25tK2RWNC9mdTNCRnlDMnB1bHF1Yll4cDZobHBDMXB0?= =?utf-8?B?TkJVSFlScUE3SjFra3haR2FvN291M1IyRFZJQ0luclU4UmZxWkRCRTRIREhW?= =?utf-8?B?N05NZTZIbWdUU0R4c0VQa2RRQjIyd2x6STBQQitFVEZtNGt0a3VaUDJ4UXNX?= =?utf-8?B?dEY5Q0FIQmY4WmFyTHJOM0tSSFVpWFFJMGNHNWtUckloQjF5N05YazhRWlNO?= =?utf-8?B?Z1NSVVJPL3JIbmdaY2NpblNNa0FjSHR1M3dXaU56YWpiZEdhTmNYY205eGpa?= =?utf-8?B?QlFidzNFU3JBODlBc0ZIK2Frd1ZBVEk1VEZqTzBLT1U0dWtNQ2VuQVI5dHlE?= =?utf-8?B?cm15NEEyc0FnL3ZSWXMyeFdoekgrUzJBMkwxQ01JWHk1U0JwNWpFMFZxNTVN?= =?utf-8?B?RUVrQ0FzS3hFSkY3SmxQS2RNOWhuclIvWDVrQlpQTmI2cTBNNFdlSTNYVnAr?= =?utf-8?B?ODgwN2hqdkdqbXV6K1A1YzhBQXlVK0tNUjR3YTdld1RZdDVTeVFsUkRMWjVR?= =?utf-8?B?VDd6a3VxUFBCVXFibWoxcDRvOTJLdVdyTGR6K2l4aGRaQTZBMkd4M1hkM0Ev?= =?utf-8?B?OWw3NEd3Z2lXV004RWxLYlhGR2RWV3VHZDRXNmZOMFNpQytjK1c1cUcyRXVr?= =?utf-8?B?N2tubFBMTDBoWmJDTFdZMzFuMlZNYzRyRXpFQ3JOVG4vLzBFVVZNTk5SQnJG?= =?utf-8?B?YUcvbGZkRGJvc2FtczZNSjNoejRnSDhBNGlWc1Q2UFpTUFBvYlIwYk54WlZl?= =?utf-8?B?SW1NUTVMeUNER1IyNzB1SUoyZjU1VHBBMXNLcjZiUStwTWdHTFFhUFJJam5J?= =?utf-8?B?QWJaT0ZHOUlhV29hU2x6bUxBbjNHYlM5QytSMFlVMVY0QSsxWVV2d3RYTVl6?= =?utf-8?B?bzVuUXQyV25naVVNclYwZVNQRmRNTGtjazIrRGplVldwSXRkMHR0MGNvYkho?= =?utf-8?B?QkNGd0V0MTk4Q3NrVUJHYTRiSDlmTHhxK2RzdzBveEdkenBjblo5bHpNWTNW?= =?utf-8?B?TTF3YnFRN2FXcHlnUWpJTGtlQnMrc3NhbnRjWVlsRXFNTTVEUWR0MmxvNHZB?= =?utf-8?B?dUJZWWUrRjhtcyt2QmFjbm91cHlCMWh0T3Z3d0hDQjN1MVpjQVRBSC96RVdy?= =?utf-8?B?WGI0M3VENFJldW4wZVB2RkdjdURWSndmd1h5cE0vZmVHZHlmTGoxM0lIdG1N?= =?utf-8?B?QWlQOXhmcVowMmNpUUorcmwwUnFmSUZidW1iVzREU3BnV05tSzVRZmJMWHVE?= =?utf-8?B?T2FwcDRKZDAzb2x0N2ttUHdFeCtnOVNDMDIwZ1hNMjZpUFJaN1VDRlk3TEVa?= =?utf-8?B?OVdYMGJ0SWNtcXVZNDNpc2VxOTRiVVhyVlI4N2pmVDZVd3dkOFh4bVlsQXZI?= =?utf-8?B?TjlIUE52aDZUTWo3RTBwS2hqYlhSNlVrdWdoNzBoZEtiUENBdVVndGFsYm4v?= =?utf-8?B?Qk4wTk4zazFKeS9Ka3dSa2x5bUQyMVptV1A4b1ZPZ25qdlhVWmQzV29FZVYy?= =?utf-8?B?cFQ1WUtMaXZnVHpKdW5uVFNCK0F1OStadEFvQUwxeVVQdUNTTFcxcjc2YmV6?= =?utf-8?B?cTVrMmNlMFJxcjA1cXN1RktSZ1Q0c2dsU3NIUmxxNG8rcXowOTRwa25uZ1Na?= =?utf-8?B?K2Y4MkdUcjRwRVoycFdjWkpLemRoeFcwV2ptcDB4Vzd2NmVmUlhKQUhreHph?= =?utf-8?B?N05NODYxOUtIWFMvTEZ3ZFZPK01MNnErN2RZYXdmbTZGL29tZHVZS0NBR2Va?= =?utf-8?B?SGVOWkh1a2JVQnE0K1VnbGVyZHhWcGt5d2NzMVFwZ0ZyT3NVVHhVQXIwRWF5?= =?utf-8?B?TVQzYmNDWGdlcGxQQ04zclFEMTBMaEJMTnpHekxtTWJNNVl1ODE4UT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 8a6122e1-0478-49c1-b797-08de9fb62b1e X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:29.0683 (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: 6vlJU61SMvVn1TYtMLIxUaMkpVCJ4xodcqxXU3/UsitaErlu79WNV+uwfUMdnb8hZTwGpTeq5urd7eoD2N4Xwg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5674 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. The way it is implemented is by adding a generic type to `IoLoc`. 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 opoortunities, and for this patch I just restricted 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 --- rust/kernel/io.rs | 47 +++++++++++++++++++++++++++++++-----------= ---- rust/kernel/io/register.rs | 21 ++++++++++++--------- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index c6d30c5b4e10..a13be8c5fd2d 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -238,15 +238,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 @@ -254,12 +255,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)] @@ -328,6 +329,7 @@ fn io_addr(&self, offset: usize) -> Result<*mut U> { #[inline(always)] fn try_read8(&self, offset: usize) -> Result where + usize: IoLoc, Self: IoCapable, { self.try_read(offset) @@ -337,6 +339,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) @@ -346,6 +349,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) @@ -355,6 +359,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) @@ -364,6 +369,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) @@ -373,6 +379,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) @@ -382,6 +389,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) @@ -391,6 +399,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) @@ -400,6 +409,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) @@ -409,6 +419,7 @@ fn read8(&self, offset: usize) -> u8 #[inline(always)] fn read16(&self, offset: usize) -> u16 where + usize: IoLoc, Self: IoCapable, { self.read(offset) @@ -418,6 +429,7 @@ fn read16(&self, offset: usize) -> u16 #[inline(always)] fn read32(&self, offset: usize) -> u32 where + usize: IoLoc, Self: IoCapable, { self.read(offset) @@ -427,6 +439,7 @@ fn read32(&self, offset: usize) -> u32 #[inline(always)] fn read64(&self, offset: usize) -> u64 where + usize: IoLoc, Self: IoCapable, { self.read(offset) @@ -436,6 +449,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) @@ -445,6 +459,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) @@ -454,6 +469,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) @@ -463,6 +479,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) @@ -494,7 +511,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())?; @@ -529,7 +546,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())?; @@ -576,8 +593,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(); @@ -610,7 +627,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, { @@ -650,7 +667,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()= ); @@ -683,7 +700,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()= ); @@ -727,8 +744,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(); @@ -761,7 +778,7 @@ fn write_reg(&self, value: V) #[inline(always)] fn update(&self, location: L, f: F) where - L: IoLoc, + L: IoLoc, Self: IoCapable, F: FnOnce(T) -> T, { diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs index 1a407fc35edc..5a7d44c51477 100644 --- a/rust/kernel/io/register.rs +++ b/rust/kernel/io/register.rs @@ -113,6 +113,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. @@ -129,7 +131,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, { @@ -143,7 +145,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, { @@ -168,7 +170,7 @@ pub const fn new() -> Self { } } =20 -impl IoLoc for FixedRegisterLoc +impl IoLoc, T> for FixedRegisterLoc where T: FixedRegister, { @@ -239,7 +241,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, @@ -283,7 +286,7 @@ pub fn try_new(idx: usize) -> Option { } } =20 -impl IoLoc for RegisterArrayLoc +impl IoLoc, T> for RegisterArrayLoc where T: RegisterArray, { @@ -370,7 +373,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, @@ -387,18 +390,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.51.2 From nobody Wed Jun 17 01:38:28 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020131.outbound.protection.outlook.com [52.101.196.131]) (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 993583D9DDC; Tue, 21 Apr 2026 14:56:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.131 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783397; cv=fail; b=mXsjUD9fIDf+Pc6dHgfpJZFFoqdHyIZMT8H7P8EMpn3mLbqTWrYo3EVcrUsXx74NH6E0gr6jZ5vp3foPCu06XXq2WthdA7tNfesDANt4HzYhIax1c5tRE2rpxzNQAVmHghqQ/Qu/PhFKRtnTGlWdDfqexkiB4Ym/GEYGqFadthE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783397; c=relaxed/simple; bh=Aiz1SAzAaI4xDUYeDbA1tGyZD1iLdIGo9Omh+b0S9cE=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=GCkYAFg2zFkQH1g9ii3vt9XJn9JoYu1PaedZ1XBgZBUd1Cu6z+BaSfYuoG4qY560QLU4PYWgqa3DEofgQtzWg2PuAV2qV3S+uqEaICw1ZfWg0FQkZdgODVC9DwtfhBspUStSBfkTJR9xXrh2lN1J6fD/ztSuaLpFlo2Qoe2TuvA= 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=IGLO17Mb; arc=fail smtp.client-ip=52.101.196.131 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="IGLO17Mb" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=DDP4tCAp3YY3lju2em9ny5IpDr/vzo5sS0bdww7i6120UPrtvhwed4zsRWFOQkfS6t1mtQ3/Oity4BUp5O6ov1m1rDeTvbDV7l1XNHzvWjpLE+mrvw+nxaamuW2xNfG6TqvNHMU9jmyjFsI1KY3SQfbUQCTJa738oJJkFwTFqGca8j17iQsTpQ/DXJHjFPr1VQI69ADLKjFHCQ1cKRZe+zvZk9etVhUnKHXtZHf5hZ20VzvGlSAJwJF2iGnBhvFkBrX7NHTDzAwga1k0ec1VEu/WuYJew+Wx3Bs5qp1EEggeW0H3Klk9uWvNTR/AXWokzMNgjGKI9YPbA2INp0Q8vw== 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=NBCRkNd4yS+sbgCTUuQCjj+vsx4wEQlficT2OEM7beE=; b=QDPjGn89zOvuriPriIbx/aAFN+A48yX0FMxZSAQ+hZi+HBSoyFO193fQEWd6inVkK4KFcNyXZKDe2BgkrUL2HqHuMMdD3ZWH/s6PRTEm2H/yDtnmHp1h2YVM8IjKz75nAQsyxGjilEBve0Jw1ufrI98o4Mu3zoN3D7aD2txZuLeB0xo/kYV7YG+M6bVyRaKd5N/MfFbgnFks9txrkXMEYJPI58Q0zs1UrpWHFnK/XFIHKNMTlqQsUCuXuPYJD4N1HPp9Xk/TEwYbeWHKJ6dmAehVNgr5XfpQLkYUcQupCfF8ei2L93Xu9DZrOBgNk07Uxozhl56hpwLV+4dKR1V35w== 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=NBCRkNd4yS+sbgCTUuQCjj+vsx4wEQlficT2OEM7beE=; b=IGLO17MbXGUWXVtGRpwpXP+pxvt5b+zSXUS88ICW0d9cj/Qu3m5nArJrH0yH/5HPCz3PwrryjfafZIV4g3HGyJvG35bkyCdccTuIF8VrO9R1xMnRojD5gPjx2SYZCQSePdKyZ03aremYQ9DtIuZB37zZ8yuOB1InblREdLnw4h4= 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 CWLP265MB5674.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b0::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.16; Tue, 21 Apr 2026 14:56:29 +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.20.9846.016; Tue, 21 Apr 2026 14:56:29 +0000 From: Gary Guo Date: Tue, 21 Apr 2026 15:56:17 +0100 Subject: [PATCH v2 06/11] rust: io: add view type Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-6-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=5749; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=Aiz1SAzAaI4xDUYeDbA1tGyZD1iLdIGo9Omh+b0S9cE=; b=nCrvfstnb2bvYiKMDfOSPCaiv0BoY0hMKfa4+nDIeuRoo33zRi9gM+3Ue8jnRMcVG39vMm/eX MtOYjTn6YtoBtAK7MWmQoyXhS0z6D+SoqXT+pPWIyVCz4q28gNytRLg X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5674:EE_ X-MS-Office365-Filtering-Correlation-Id: 28f11079-18c8-41d1-7aa9-08de9fb62b5e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: 7J5YxYfOO0KE9wVilg4vvkJUIbGrUwPiWBY0LsonuhnDZB4JhOct5I3UyjF+C1qnPnEu1TH2S9DcoO0EyENcaoCuq6El9fAOTgbbXu//aul7GFTNAByIJuQ1uIzAyNV9zlGKcM6BokQ8v/YwSpkxy1TB0tdMW0wJwZt/Uuioqb3CRr6UBtpYkfIJhw7RhqueBo6zlKlUTXOqkrOUYgCyzD4+aKftfoMGi3p9ZDUZDEvRGf9YivBMDTjGaTXobFok6Ao7lIdRgDBnaN80jvyMERMdjNyYiYbbf1iEM/SGNRuNADgmwBLZJV+kK6pZ/EjGvsPLk6bGsxof/ClW3EBcQA3CKXinBLBNQbdi3X3kvsllSMaiY+bEjazj5H6V3fEZgVfE4wzVlNWF8khhiMcYbdxjFQajjo31D7GqbOaUwl5gJLIGNGV1TyanDpVCvoUlq8LblLyLglSExElXTtHhVS5dcYELhxZiBr0UA1/FUYt30H6czbfVmwUdFz9PUpqzOsAbOC/Qyy/n6v6zEZsKXtDC3gqhU+iuhFLK6Mearg1ZxmUzwHzQdyVk/aSn5DBpsXG3VsjBuQ0+O3OZGQKM2A+B4HmCpfQzfcLxBcG1MBtwQbEW1ShJK1fK/g0kbdEwGeIRbGjZrMziQZKs0Qh8EkRY06xYBWMmVPPvt91ejVGAjrNUA8S6nJ0EzwTNFeN3qInIhUCVm56mrQhLUeBQlO6WXZY3pmQEKtIJIgBUuVh+n2PiiR03S4Y/RTCR2j1otttrFbsgH4TqOZ4vnaYCsQ== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?KzJ4RzYxNHkzS1hZYXZHaXBDd1JFRGJVWVpoMXZqaGxIcHM4NllwN1VYVjZ3?= =?utf-8?B?VmhwTmE3M1VlalhodGdwZE5ra2xRejFySWRjNS8yd0t1b1hGN2dHQkFjUUkz?= =?utf-8?B?Z1FhRmVyb1VuSE1Nd2FyMnhQVFFXL1lBc1dxU0EySVFGMUt4Vlkza2x6RmhZ?= =?utf-8?B?QlB1bjZUL0RMT1ByalV4UHBqYzJ6b0IrWmhONlZsOWNvOGxCSWRrVi9lUmIr?= =?utf-8?B?ZWpIR0RXUEcvQkZ1M3M1SURxTVg0QkI1T0crMDh6UUtUeS9XWW0rMjNwekdo?= =?utf-8?B?NHNnNGt4cW1zSFN1VTVJQ0kwYWk5aFFBOW1RSnB4NEdxY0RWUEhBckpqYXU4?= =?utf-8?B?RzNFdVVtalViVTdtVHN5TlpCNDhHNERXUUk5YjFpQzZ4NzloeWs4VVFjRFpC?= =?utf-8?B?TVNjK1pRNVEySzc3WFkrclZOaDhCczMxdlcvS2czeVRDUnJpNU9ENDVaOTdG?= =?utf-8?B?YkpwN0x5b1B3N1VsT1JtOXVKSE5jOEFwSDZlNENNWnFLSDUyWGYxYjRQaVE4?= =?utf-8?B?Z1M3R1FnTHRSSkFIVThtZWZvSFpoTFNOcnpKZkVlQ2dOMHB3eXQ0OTZHYlRC?= =?utf-8?B?akhvVFB0WHY4UDR6ZFBMeUtVSk1KK2RwazdwVENlNkVhNkdYOXJ0clVMajAy?= =?utf-8?B?Y3JkYXRlaTlSNE9RcUI3TmRtNnhXcG9zMVFabjNqeERHaS95S3o2VWZlQk1x?= =?utf-8?B?c2FjNklZcXdUcmxmQkxvTE5lNzYyd2oyNVBPbTBZUE1haVUwdWswUVdRVEcv?= =?utf-8?B?WUZmV3VlNTQwNjlTV2VjbC9ZdjFPa2h5bW9VMG5GR1pWT0FjbE9vTXh3NGNt?= =?utf-8?B?K3pBQXNiTmRleUtuY2xDcWp4V1lCZXVEUmswaXBJVkFFUjVGYzA1UDNtRUEy?= =?utf-8?B?M2N5WXR5dEM3QzZDNWIzUEVvdXo1V0NJZTlaK09EdWtqajN1cXZ6NVJQdW5q?= =?utf-8?B?dXVNZ3R0SURSTnl5alR2VFdZd1hWYmtvYWlVYTc2NkEvQzJwL2dQS0dMMkJO?= =?utf-8?B?djJoYnpuWDFhb0xYeE44dnplV3ZnQy9RandPMXErVmhwZ0NZcjdTTGJCOTlw?= =?utf-8?B?MVQzUTlzUGFXQ3ZEVEZqNWhVZGN3ejdwdUJHbGw1UWl5ckx3YlB0TGNSVFNK?= =?utf-8?B?YzQyRE1pZ1pPSERqOVhMS1N2VmdZWnplcmxpTGdaRFBnL1k2RERaY2swK0FS?= =?utf-8?B?dHJJcDk5bGJ4R3BVUjlCSlpmWUp0L1Q1WjcxdEgwd3dRamRDNHloYVRmdUxu?= =?utf-8?B?eWNDY2I5cEVacWlaMCtuWXp4RjlpeHY1R1BaamNpb3JycDU5N2pyKzJISXdp?= =?utf-8?B?dCtQV0VJa1E5NXp6ZnJnVWVWQ1pyZG5HRWF2T2RoMElQTloyd3QxSWd1S01r?= =?utf-8?B?L0pSRFMvZ1lOR2lXZjdXY0lOWXdXNW0zeDJUb1RvcU9xWkVOTWV1UUVvRjJl?= =?utf-8?B?TWxZQWljQW9PQlJTeC9mUWlHbGE0MU9mZm5Ec21qZGF5anhZYlFUUjRNWklu?= =?utf-8?B?SXI2a2MydExUVFVLdmIwNUdjTXJ4UnNNNXlRK3pPS1RKNXFlM3dEQU1DVk1m?= =?utf-8?B?SkkyV0RENHRwUjdnSFNMbzJ2Qlk3andoT1RjYmZYeFdBZ3A4Znl4bmRudXFk?= =?utf-8?B?ZFltMmxKdDJXcXdhZ2tuTVhwUFZ0cUgrSTRBak9URXg4MVYrazE3dS9yMW1y?= =?utf-8?B?RzFmK1RzR1lyQzh5TVQ0NitIM1dRVFBJS0liMUxFSi9haUZqc3QzOCszSENR?= =?utf-8?B?OWRQOU94d0RuRzVZRFdFZWw1WUFaWnRhWjIxYzlrRjlwZllqdkwxYStqR2JL?= =?utf-8?B?dWo4bHUra0l4TnVhVGpIR2ZXejlyR2NiZFhuTHptN0s2clBlTnpCNXVNT2tm?= =?utf-8?B?MkxTZ3V4MkY1R2F1UXMyYjJTWWRFUUpRMGg5dWVDd2NDVUdoZHB0S3RwNkhS?= =?utf-8?B?MkdaWllndVh5SmEzbFNJVWYydDNRdWpwRGRzNnhRamc1ZnFjbS9FcEZSY0JT?= =?utf-8?B?N3FjenMwKy8zZHptdHFlelhHaG93MmlpNGRRcUh4S0NzSktRM29rdEtMVVp2?= =?utf-8?B?YnNMdjk5U3IxeEd0K1hnejJaR1NJSm1mWDVzZkhmMU50SE1NejJDNGI0MUJW?= =?utf-8?B?UkZhTkdEUk1lbnZmckFpR1BpYWxPdnMrV3ZFYmpzYVdYNjk3SVRQN3FPQ2N2?= =?utf-8?B?MDR5TzRCRGdmS3lmb2lXQVFSYVBpNjVHalNxbVF5YmlLT3pGU2JpN29ON1ha?= =?utf-8?B?SWw1M3RuTFRJdnZya3IxLzNuMXdQUzF1cm5TL3d5Z3RBdDNoaVgvN1hpZTVS?= =?utf-8?B?RU1sUWJHWUx0K0N1dzU4MmtVNXlkV3VFbTN4L3lsUWhNZk5zVlRuQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 28f11079-18c8-41d1-7aa9-08de9fb62b5e X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:29.4443 (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: 1Syz8XJXVkI6KKLCpM9rZmI6lTHNlMxjzta7D73csoPArsab/AkmuOkZk9NFHov1vgmuOBQRP6XHP2OMMxVyug== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5674 The view may be created statically via I/O projection using `io_project!()` macro to perform compile-time checks, or created by type-casting an existing view type with `try_cast()` function, where the size and alignment checks are performed at runtime. Reviewed-by: Andreas Hindborg Signed-off-by: Gary Guo --- rust/kernel/io.rs | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 146 insertions(+), 1 deletion(-) diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index a13be8c5fd2d..869071d47a13 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -7,7 +7,11 @@ use crate::{ bindings, prelude::*, - ptr::KnownSize, // + ptr::KnownSize, + transmute::{ + AsBytes, + FromBytes, // + }, // }; =20 pub mod mem; @@ -297,6 +301,13 @@ pub trait Io { /// Type of this I/O region. For untyped I/O regions, [`Region`] type = can be used. type Type: ?Sized + KnownSize; =20 + /// Get a [`View`] covering the entire region. + #[inline] + fn as_view(&self) -> View<'_, Self, Self::Type> { + // SAFETY: This is an empty projection, so it trivially satisfies = the invariant. + unsafe { View::new_unchecked(self, self.as_ptr()) } + } + /// Returns the base pointer of this mapping. /// /// This is a pointer to capture metadata. The specific meaning of the= pointer depends on @@ -912,3 +923,137 @@ pub fn relaxed(&self) -> &RelaxedMmio { readq_relaxed, writeq_relaxed ); + +/// A view into an I/O region. +/// +/// # Invariants +/// +/// - `ptr` is aligned for `T` +/// - `ptr` has same provenance as `io.as_ptr()` +/// - `ptr.byte_offset_from(io.as_ptr())` is between 0 to +/// `KnownSize::size(io.as_ptr()) - KnownSize::size(ptr)`. +/// +/// These invariants are trivially satisfied if the pointer is created via= pointer projection. +pub struct View<'a, IO: ?Sized, T: ?Sized> { + io: &'a IO, + ptr: *mut T, +} + +impl<'a, IO: ?Sized, T: ?Sized> View<'a, IO, T> { + // For `io_project!` macro use only. + #[doc(hidden)] + #[inline] + pub fn as_view(&self) -> Self { + *self + } + + /// Create a view of a provided I/O region. + /// + /// # Safety + /// + /// `ptr` must satisfy the invariants of the view type. + #[inline] + pub unsafe fn new_unchecked(io: &'a IO, ptr: *mut T) -> Self { + // INVARIANT: Per function safety requirement. + Self { io, ptr } + } + + /// Obtain the underlying I/O region. + #[inline] + pub fn io(self) -> &'a IO { + self.io + } + + /// Obtain a pointer to the subview. + /// + /// The interpretation of the pointer depends on the underlying I/O re= gion. + #[inline] + pub fn as_ptr(self) -> *mut T { + self.ptr + } +} + +impl Clone for View<'_, IO, T> { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl Copy for View<'_, IO, T> {} + +impl<'a, IO: ?Sized, T: ?Sized> View<'a, IO, T> { + /// Try to convert this view 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. + #[inline] + pub fn try_cast(self) -> Result> + where + T: KnownSize + FromBytes + AsBytes, + U: FromBytes + AsBytes, + { + if size_of::() > KnownSize::size(self.ptr) { + return Err(EINVAL); + } + + if self.ptr.addr() % align_of::() !=3D 0 { + return Err(EINVAL); + } + + // INVARIANT: We have checked bounds and alignment. + Ok(View { + io: self.io, + ptr: self.ptr.cast(), + }) + } +} + +/// 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, +/// View, +/// }; +/// 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: View<'_, _, u32> =3D io_project!(mmio, [try: 1].field); +/// let whole: View<'_, _, MyStruct> =3D io_project!(mmio, [try: 2]); +/// let nested: View<'_, Mmio<_>, u32> =3D io_project!(whole, .field); +/// # Ok::<(), Error>(()) } +#[macro_export] +#[doc(hidden)] +macro_rules! io_project { + ($io:expr, $($proj:tt)*) =3D> {{ + // Bring `as_view` to scope. + use $crate::io::Io as _; + + // Convert IO to view for unified handling. + // This also takes advantage to deref coercion. + let view: $crate::io::View<'_, _, _> =3D $io.as_view(); + let ptr =3D $crate::ptr::project!( + mut view.as_ptr(), $($proj)* + ); + // SAFETY: projection of a projection is still a valid projection. + unsafe { $crate::io::View::new_unchecked(view.io(), ptr) } + }}; +} + +#[doc(inline)] +pub use crate::io_project; --=20 2.51.2 From nobody Wed Jun 17 01:38:28 2026 Received: from CWXP265CU009.outbound.protection.outlook.com (mail-ukwestazon11021095.outbound.protection.outlook.com [52.101.100.95]) (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 0C41A3D9DAC; Tue, 21 Apr 2026 14:56:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.100.95 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783401; cv=fail; b=K277uUiGqIwjq2piGUrabQuSVpVsnsJBK0MuQmdIJcSvzQADdt+Yp3rPyqT5aWolBPs19q0ArS5IFQzNTz/UXPcaeBgSPSidfujeCf4ICNVzlnoMrulxwgpr55eGbTMiGy4DS4J8/HogXFQdeBCPY/BU8choQfXETPqBVWzXP30= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783401; c=relaxed/simple; bh=aOfLPip234jwbtfUDxAEqballSOb6fOW5cF0Oh7xboU=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=m+XRNsHmLUQcLFSbVKYyeFxo5q507nWLxUWSxtGZpeDX/tWk88l2flLdKrtgG6eMfSoSDw0Ricr8hnOBDYJdKRQjKGUCaDs6ClpseQcpnwklDqq+QatbJewlEN8BkM+HXxNJwnV0Df3AeWfYyFuu2E14TNk9hk+bSshqa+3sIjQ= 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=W261OWEU; arc=fail smtp.client-ip=52.101.100.95 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="W261OWEU" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=G5Z9y3acjMC+zGKZnH1pF9j3SwpJCGv0tc8M702z9xfxEx8kweG1NVxsRAoWJUmMkWjiv9H+KBDxDY3rqHAR+8p117jyaPt6p/GBZfL+YQcMgkffx+7rhb5QiNdefOLh2B50csWjJr/d+HpnvKeOXF+Y7EEUZhzf9V8WcSzJvi5P6/44v7bsXB6WT8JjQD9I9O1B8tnEvqNmY+D9MC3HWLBAgH+TaCaQT3UToexpw5lnD8y83MfW1XVgbUovCRXdZL6gznaCZ6+jxVVMyg8WfBo8pPtcIUFhJ3GZFG1r/wnRW39g06NFFO2tniTKpG1SYuRPrCADxt8TlNAn9MmVXQ== 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=vXLe8WC7UCzcv5FezZO2TXpBmQPZnCQW8VAR9ImGU28=; b=hEOu2tEvK29BwVWqsEUwM4bXxoxCyzKCbzn7x/xXx52iTa7hvesMziyD3Au/YEneX/+hX4yK8uEWTnAfwvVRZqVljJVJXlRbP/12c2lf+7foL1bbSyYdX/ji8H+IAKkG/IqMdVTaNDfmJ8x8QH6ALcbhl8Eab2o0qpYizXECujSb7qf6QeEcr3FykxImSh1pmwAtwWk7KdKZvFbg0iI95sdKQRingJRU4kwFd6xZ2+YetfraFB9Q+6Jff/i5Byo/qS+9we9clD7gTodHIYo5TpJfnkDXCOHU9xlpruAnbOg3XNiWlmdEqOD7lRYkpw2TICQfBZG6lmzCEmo41r/hWA== 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=vXLe8WC7UCzcv5FezZO2TXpBmQPZnCQW8VAR9ImGU28=; b=W261OWEU8baWiolRoGviCQDonJGZ57t28SUEd35/0TjcHPvRblye6nLkeGpQSEy4Q72GzClM8NDQLupe2qrm/jkVmhmkJMV7v5N6mE20fw6IJ58+Lm4BZDTOEeQcGdmRwvHf4z9tKtVoie8uoXrVljRKIgTUtbmUGhLq5tOOU3U= 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 CWLP265MB5674.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b0::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.16; Tue, 21 Apr 2026 14:56:30 +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.20.9846.016; Tue, 21 Apr 2026 14:56:30 +0000 From: Gary Guo Date: Tue, 21 Apr 2026 15:56:18 +0100 Subject: [PATCH v2 07/11] rust: dma: add methods to unsafely create reference from subview Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-7-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=3238; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=aOfLPip234jwbtfUDxAEqballSOb6fOW5cF0Oh7xboU=; b=9cwJCopkLJXLfv+fchvQXU2DAVsu9tkTmCIoRC61SlzZ7JqVJKLjnY7m9FcMHshN3o/tpWmGu eece+sVYDhlCTmfdJvjXTSH38fFJxTltLkHqs8un0ekriNLG//JKnNR X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5674:EE_ X-MS-Office365-Filtering-Correlation-Id: 0e47ee9d-3303-49aa-75ad-08de9fb62b99 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: PKeaGTdBH7YXZxXtJ+UU8G4qrqRLQvvlFf4rvHURRzJ6pwaVlmtlM2LUlocHjvBIHkcS6+12VOEcWWXrGZQDOc+w2CwPx3k6v1QiecJpVmwqsExdb/dIxpmITMiw5ZCxQUBO6R/sGSZol5qmGXRBxNrfuQwQDE6sLvesOZ0iEzVr5jLHVRPtuCYMJgisDlcHxt+oCM7xIcNnf5PEfXK2F+mTti3iTHfR/r5fDfOeE3qhU2RR5R47MPUDcEG3nvWLTuyoWuSiu8iwdgMreCmw0Sy8MrG6MIVQ8wA83H7VqiCQElFTFX8Q2DVkXToSINl7XHFOVylS49GWlJT2PSMg3AZ0JdZZo6MMknCoiaC/U1bqdlyeG2LL2n/0MxHkOWC3aJaIfF6IPOLOlPRjijnd7x3S13as0a0dPvQ6HFMNmCuKcmG/kuV20tngjhpmVkbSwAdIPx/ROvxlcpLUAqLlw26DMZXklQNbR0Yn63bzp9UPx1+lkCDHlWEVQ7QvPPMjt8T3PI+9/FxDybX/GIGBJxcEM/1xNe0HzQaSv5HtADU5FKjNLAJaW5Wv9sxILd9B/FT34wPCh1v+VwtwLNCbI0Ye6SxCMiRq+BRpxNqD6Njvpq8R7LZ9C6GONozjsHirPThODHDV/SNTABuLOmnFGHrukc3ixHfU4ru6gf4aBbwjNXmIaqCv8DsX78lyynECtI+An965Q+2rjJjpE2tcTppQLEm5wnW0OqmZr6oBgL0AOvb9RC4QxmVrwNXdhs962XER8Rm89OYxbD3UFRawZQ== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?OTc3L2dBQnJkemNybXNOQjZ4YVFvL2UzSklVMHJtU1ZVV0lvOW1lVktWUmFW?= =?utf-8?B?ekMyZzBVTzl0dk5JaTZIK05GQjBnK2FZWjFUZGtOdGM2YmEwby9Wc2RHRkMw?= =?utf-8?B?c0V2cWd6MWhCdVFXek9qMzYzVmgyNFdqQ0ZxMmd6VThhbDU2T0tZS05Pa21H?= =?utf-8?B?aUluZm9aQlBCdWl4OGorZVNDR2EvUEE2dzQ1SGo4LzZCSWVkdy9IbDRmZWUy?= =?utf-8?B?SU5taERJaVNMNi95SlFiKzZNWDZUOWZXOWdzZk1DelVXNWdhdTZHQWhIS0FB?= =?utf-8?B?dW5oNmh5eWZLQ2x4MEpKSHVZRDBNVGVOaFRCSWlES2txSHhRbDhhSEoxQmVv?= =?utf-8?B?RkRLQ0xPdnhpRll1dm1ZOVZQUGMyUS9MSllqVGxiK2Q3UWY1ak1RNHFhdHdq?= =?utf-8?B?bGpQL3pLRGliU2VLOGU1S1N2Q3M3RklFY2xQNzdENDMzb3dWT3lMdmZLMXNS?= =?utf-8?B?ZTJaRWNKTDhrMDNIVlYzN3ZuVmZtbnVDMGNlbkF1WXJURm9jOVdQQ3ZUZzNN?= =?utf-8?B?Nm05Q05sK1BBenhkTXRVMHFqaTJzb3o4QVpoN1B1akFjL0VEUkhtRFFHS2Ns?= =?utf-8?B?QVRoWjNjSHV4b2xMWmowNmJiM1M5SjZURndYMUlBejYycm8wV3lLWkFUaW9V?= =?utf-8?B?VkNVVFhRckc2OEtTTzdKbHlFNXZsQUVIYjAxT2lVdTk0RzVKQSs2Q1lVKzc0?= =?utf-8?B?aXd1dmlNdndVZmx3OXIxakczR1VSMW92bzdPOUhCUmVhOEE5MHBEeDVUdExI?= =?utf-8?B?TW51RFpGbUlxb2Z4NUZCalhYVFhQdXppTnpiajh6a0wxRlBEOTEyVEQ3WHI5?= =?utf-8?B?V3dXNkVRaTN4eEg5MDAwcTJleng4U2lTeTE3dGE3M3B0NHhscGwxUHRPcVNq?= =?utf-8?B?OXZKOTNoeVZVNUIzR1kxNHZQZzFKb0svMmUrWVZsbGxVWGNsUDl3Q0ZGQjRK?= =?utf-8?B?TmRTbjZWLzRWVHNsNUFHQTE4RzVrV0txRGF0V3VPK2pJbWo1RlVvempPY1JV?= =?utf-8?B?bWhCaHI3MlhxTjI3R0RyanJzbEVHU3lMMnkxdVVUWE1XY3c0QkR0c1phdXE2?= =?utf-8?B?RkRORDdDZFIvSjc5MFV4dWYxcFQxRVdrL1FBZlBUS2h4S1l3WVB5d3Fqc1F6?= =?utf-8?B?Nm5nMERGYzllYmNHaWR0MzJQemdWL1NjaVdkWW5CMU9QRU9DU1NGbVVwNnB2?= =?utf-8?B?RUw0TURJNlZGWm1tcFdxN0ltK1lzeTNzdU9DZmttRW1ENXIvc0tYWUxNWTdH?= =?utf-8?B?TWk1azNoblFhUlY5U0FjRHowTUZoazB2a0hUSVE2R3YveFVlZFg0bWNIN0ps?= =?utf-8?B?cGRsQXBsQmVkbmpuK0UwaGdEMnVzaC9IWEc4OEZaSUpNU0xzUFBYcUtUcDUw?= =?utf-8?B?YklpUzBLRCtSUk5sUElWT2RMTi9JSDl0Z0ZVYUtsVVUxS2w4emtYRDlTTVQy?= =?utf-8?B?am5kNnMxMS9oL2JrTHdDeGM2QTB6ZDZYbEROeDdaOEUvL1M1M1FPYUoxOU9E?= =?utf-8?B?UGQyTjRTd012clNIVG1Zem9oTVFoUEpxMy9ZWUI2TFA5TGZmU0pTdkttZXBz?= =?utf-8?B?TTNYVXk3ZysyWVJIbWFXTkptNUE3bkdZUGw4L2czdTg3aGY2em1kWFN1dlgv?= =?utf-8?B?SkNLNW4zVDhHcXVYM0dXVHI4K0R5V09MSlFyc3dEOUhRcGNkSW1ib2I3Y2Qw?= =?utf-8?B?ZXEvMEJjeTdibDZJOS9BbWcvdUJSZk5iaXBsVFJKVGtwaEh1dkI4MlFFZlBK?= =?utf-8?B?Q09jRStYNkNPclZyUEZDOEt4bzRLcWZLUW5TNU1NVkdBRFVKTGxXL3BRZ1Vz?= =?utf-8?B?bXEwaVNnQ0VSRk5xcjdvUWJCaTlseHJZMkNlekxlSFhmcUwzdzMrYlc2Skpr?= =?utf-8?B?ZHAxZUI3NWJudGJEbnorVjNZQkFUZnl1Rk5FWldCSzlETVN6bnlwdGZkYXha?= =?utf-8?B?R0F4L3VMV3RmY3lFQU1XcE5Oak5pV2h0cmJzNlh3ZVR6N094SmdEWjdscW9j?= =?utf-8?B?bjJvN0lHTklKVHd2ODlXcXV0ZGFFNWp2S0xLeEowZzdMUEI1WStGSWM1ek96?= =?utf-8?B?N1RzOFVVTTR4ZXU4QnRDMHhlTEpwMlliR2hIN0hnY2NJZWt0NWhhdmd4R2tX?= =?utf-8?B?YTBxdHl0cU1xcTI0dHRlb2U5LzhqcFBHSTljZUhjRm1ob01SMDNWZVBOUTNI?= =?utf-8?B?YUNyaytrTkZzMVo3b0tFUy96WWVjSFhLekVoY0hmRytveW9qKzRZUUdlWFdW?= =?utf-8?B?bjZDdmtjWHB2VzY4S1BqS3Y0YndBZmpQZkdPV2p3dURBWVYzWldUSGp6YXQ0?= =?utf-8?B?TTJiazZ5TmU0bUpETTJvbGEwaXdWT2IrYzI2TGIzZnJtZTBtbmU3dz09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 0e47ee9d-3303-49aa-75ad-08de9fb62b99 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:29.8300 (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: vQ1NfKZA/lhJvrbTUcgVxAwapgPD+yibre5kogvYC4UTqBmW1rlObAfVSfaU8KPS3AE0rr46h4vEPCZ53HQHMw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5674 Implement `Io` for `Coherent`, so now `dma::Coherent` can be used with I/O projections. This allows the `as_ref()` and `as_mut()` API to be used in smaller region than the whole DMA allocation itself. For example, if a ring buffer is shared between GPU and CPU, users may now use the `io_project!` API to obtain a view of the buffer that is uniquely owned by the CPU and get a reference. Signed-off-by: Gary Guo Reviewed-by: Andreas Hindborg --- rust/kernel/dma.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 54 insertions(+) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 642ccff465c8..92db0e58f364 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -14,6 +14,7 @@ }, error::to_result, fs::file, + io::Io, prelude::*, ptr::KnownSize, sync::aref::ARef, @@ -989,6 +990,59 @@ unsafe impl Send for Coh= erent {} // The safe methods only return metadata or raw pointers whose use require= s `unsafe`. unsafe impl Sync for C= oherent {} =20 +impl Io for Coherent { + type Type =3D T; + + #[inline] + fn as_ptr(&self) -> *mut Self::Type { + self.as_mut_ptr() + } +} + +impl<'a, B: ?Sized + KnownSize, T: ?Sized> crate::io::View<'a, Coherent= , T> { + /// 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 { + let base =3D self.io(); + let offset =3D self.as_ptr().addr() - base.as_ptr().addr(); + // CAST: The offseted DMA address can never overflow. + base.dma_handle() + offset as DmaAddress + } + + /// 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 { + let ptr =3D self.as_ptr(); + // SAFETY: pointer is aligned and valid per type invariant of `Vie= w`. Aliasing rule is + // satisfied per safety requirement. + unsafe { &*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 { + let ptr =3D self.as_ptr(); + // SAFETY: pointer is aligned and valid per type invariant of `Vie= w`. Aliasing rule is + // satisfied per safety requirement. + unsafe { &mut *ptr } + } +} + impl debugfs::BinaryWriter for Coherent { fn write_to_slice( &self, --=20 2.51.2 From nobody Wed Jun 17 01:38:28 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020131.outbound.protection.outlook.com [52.101.196.131]) (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 83F363D9DDF; Tue, 21 Apr 2026 14:56:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.131 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783399; cv=fail; b=DO+ulg20RBmdCnb3QuFex4boaqqFdzZmT5WS6aeHOl26wHb4mHRKx4ke4dE28DcHqsU0ssE0dmobv+jCFAFlawfIZDS2Kk6rdRdf1JWzNKTmEft78meOI2VWhh/+qdsdDTqvMshMTyNifxSfVlzKrR94svKCyK2xbb2gqfSdV2I= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783399; c=relaxed/simple; bh=d7D59E81y7GC3frEJZ83WlP+T/kdXpX9ZQKPVZqa7+k=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=X74EJ+Bv3s7DEcNVasivvIJG0CYB5WGzN5zJMawb+KBHcpOUreGAWQ1U4fkpOY1XH263xeHKx+R6dzPicC3vE0qqgo4tVffQvW8EAD89w37rV4Qa17TLPyz7ZeH/mEVio51B67/bQ/v8bHDV/MEb2PRFlYJuzJooTTr9YDpek/0= 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=hhhCA9/e; arc=fail smtp.client-ip=52.101.196.131 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="hhhCA9/e" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=CA40ceVExwfC2a5hzRTrRuIv7zlYRc3s+bT29eoKQE4/JkNSTZEroMN+aZQZXY/8KVFYuaWdCbdPMuCw1kY1Xv0umJmoal4TVzdCZf68AMuwNoAVEktHd1QNKbzO35YUaZymwZ76CegTnUuuGgfe+YyhaQRjbUAbG0wRmyPOyPY5YuwOnV1lm3+v7z64i1vg+Wu6PPvfm79Eb+WRixJwoAbFd1e000OBWVNJ7C7i6GXz1n6T2OBVbxP50Ktl6OVAYYELlOxUI74fShu4l1jedQGL6pLcpG3EJawlnPwE0psKep25YQpiFFoYT8YzFJ5/FsdzPTYFxGLQeXA/Ann+2w== 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=1b5DdLMRYimSWgJfRYYszp83aLSNpWhflPrz3Msjbw0=; b=hpCp5b8vX7ahgq/LOBhGNQhead/98Lo6zxB4CgPEj3+E3sHbL3v7ZwVB3301PmKz/Q5vvYT1fugUqlORmmLvuOaeYmaajDyTrQWEbJp3aj6KuFSHpEjDJkuBVNsqNSVOHB7MtygGHpy3APC+m9VBFFQe45nnw2iq+lBJKGiONgjLta7CSYRI9cbr1yhNd6Olkn6C2r6IU8wk/kcgIktkxQmU2nysnkVbSdO7GeZKSPCnH0rUji7uAMrMNkFce+4CC3tEQRlHcZLW3zv4MD0qsHFyrDhtCE2sFnJcb+HVWzWizRvWa0huLzbonyXeTujRn/ur5GOka0g47d9nZiiRRQ== 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=1b5DdLMRYimSWgJfRYYszp83aLSNpWhflPrz3Msjbw0=; b=hhhCA9/eaU+Y2JxIMiWifeyArKcf8914Y5HeeyehURYll+lka+wj/96SUr1/oaQjKdx+7d/hscyc95Vl88XYk5Y0IFxuAqf0y+ykY8Y5qsmpnpLkgn8/GIPzmtcGX2YglQRf0rM6qTHxVCSs7j9ocE/+LE3vEz0KXeO4nTTT01w= 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 CWLP265MB5674.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b0::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.16; Tue, 21 Apr 2026 14:56:30 +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.20.9846.016; Tue, 21 Apr 2026 14:56:30 +0000 From: Gary Guo Date: Tue, 21 Apr 2026 15:56:19 +0100 Subject: [PATCH v2 08/11] rust: io: add `read_val` and `write_val` function on I/O view Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-8-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=7273; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=d7D59E81y7GC3frEJZ83WlP+T/kdXpX9ZQKPVZqa7+k=; b=qF0wrVzmyz8fm5OQ/DwWboUlelLDg5mLGSN9s8IcpY5U5Exs6P6m21qpLlivvfZa17vP94do/ kKKGzRhLwasA1tPQWtMdNqJP/9gWsCBFWZm5puOfvZYSBsBFUf0lnX3 X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5674:EE_ X-MS-Office365-Filtering-Correlation-Id: 7dacd265-791f-4be1-e56b-08de9fb62bd3 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: mEroFlZL5aM9woDSdEslRumUUAayC5Bu9Vo1ZdLU++sa1r1zmKX40nBagHzx1YHvrkUKB0Pcv504JAyUIe9pWnXIA8kQECG2WeWO9dK9gv2HDCd1t0KdHb4Ys2klOoIHUFcmmp034PefU1+HwWowxxOqUs5/eH5DBaHd8ZpGieRpa6xc/Go6Ro3/+HK3X/i0LogvXzKZSwpIbQ5hImsHW0N2UGbMZb5sTD4VgrQEDUZ7+fcBTM/jdzAQcd6HewAYy8aSjkERcfKAKAmmBVFOM6F0Ibz31PCfN+aDjRXrV9LyVoeo1e0j2zi38rXQWqVkM494KSuSk6MZfevhqmxFJw5vQ5W4Wlnlgj6APhdxHv2RoRYE/dE9Ap6RhmY2zpoWsiwvzorRodt7uak25bcJ12jrYcKv3jmRyJ20SDrYhq1KuVKOh9FjFr3Y+u7Wqs6U2B+0l/GDViZcbq8lpaEJY2SCl0IzURkHgk8Dn/HnJkSWrzl5qYoQtJzhf8MZmE0Nxr0heaYlgYYPtIGmaD3yyzKmdybhZETbHgOk9BIR1gnAzIxMxrJbVjZ7KGAA87qrbOAotxPC14wUoDhoZ9iOO4v62XJ6QWEYdsm0Y+UjCcuxdV0RaxopFXuxFOhzjQUnXdcm0lEvvOY+os3AEKD00Cp4DOUc+adHEaXGVSpv6fQ1JnoEfx6KwjmhvxCyVZeL9H1h66onjEPyP8Toc5L2Q1Pgk45yu1cSN+RO0CqgkO8CcWWc3PTe+zCer3BPI+D1hf1IyHUHtx/sklf9iFcaZg== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?S1N4WitMbFVKWVpLUkhVVGwwak1nK2pQalhHQlJubncvZXZDVTlrNHgwUFpB?= =?utf-8?B?MGltUmdWeDNaVnF4UklCbytlOVg4dDY5VFNYUlNQUUZudVlUOTV3MExObFoz?= =?utf-8?B?UUhFS2ZNSlR3WlN1SkVmSlJ4UTlMTUZ5QUVWSTNKZGNuRFRGcC84VnZCWU1h?= =?utf-8?B?dHNWTHZWRDduUWxIR3RiNG9UK3RaTkhhd1FDZWxETXFmd1BqV2FJMjF0WGd4?= =?utf-8?B?aHZaMzRiOGxEbWRHN3crZmh0eXRvTlVDdDM4RkpUTGZVMjVEM3J4VVN2N1Rn?= =?utf-8?B?dk5ETGV6STdmU0hSRHFlQzhxTEhiaUIvdlFIMXdpZ1ZWTUdLTkFzWThRTGZa?= =?utf-8?B?ZGVVNmplTlJGNjB5WGllbFJINHJseTZOYitsOVhUYStMQm9NZ1l5d2tWdWpF?= =?utf-8?B?Wm8rWXpzUi9BcHBSSXpQNzhiNnFzdHlGeGFZdDZMRFNBNkdvQldzdGgwYVpm?= =?utf-8?B?TGR0ejV1SEpXdDFvcTVJNkNoRmwvaGdtY3pLNllLaFlES3JPYkhWYXFockJ2?= =?utf-8?B?RjNmVXU0YnlQeDRxdkFVNVE2aWlBSytSWW56T0NZc25jTFBLNUtMMUJRZzBL?= =?utf-8?B?d2xEUjE2NE1qeEMrYnd0Ym54L25EU2p1em1LSytSZjB0OHM4eURuUjg5akZK?= =?utf-8?B?NlJQZ2lkMUJCT2ZhbVh0Z2N5UkR1WHZndWlFck9pNVJ3c242dnVieFU5dmFY?= =?utf-8?B?NXQ2WUFIbng5UXNib2o5WWFQQzlFMU1tY0RvTWVXNkxzemlLd3lQQ21nMENo?= =?utf-8?B?U3dPanNsVnNvT1Rza0JaWnl3aExrMzZNc3VXQlduMURkT2ljWmtkYjFrSnJ2?= =?utf-8?B?QTFITzNrcjY2K1VUWGVrRCt2cWZUdWFyL1FiZ1g5OFVNQkprTHZuVHhTRWd3?= =?utf-8?B?a0s2Z1V1Znp0MFI4bG9wdmdDWm9WL1AvNUF6ejE1US80MnJQSHNvcFU1OFFX?= =?utf-8?B?R3p2M3pPdEkwZU5QSWtwelREcG1JWisxdUdrcHB0UGNBNEpTVHNsdmpqUEIy?= =?utf-8?B?QTNldWwvM0JEMkg0UzNQa2FveDZXWXZXYlBJdytieTNLRkgvbFZ3alQrenYy?= =?utf-8?B?eFQ0SEttSTJucVMwdTVReHk0K0RnQk9oclJRUVkzd0VpbjR6NURpblFuOWl5?= =?utf-8?B?SFlqUW5xNUpTQkVMRzB6eGhPMFEzajI1QStXbDdIUFRhV204S3J1WDE2Wkt1?= =?utf-8?B?dkJoUjhzVjVjMW0ycDJSeUhFbHdFbVdkWFB0OC9vdSt4Smt6UnZYQXZoaVFk?= =?utf-8?B?NFkxemRkaFNFT05JbXdqbWJBY2dpZDFlbWQrbG8rMlAyYm5SNU4wa0l1VXl0?= =?utf-8?B?VG9HWFEyV1Bnekl2ZVpOQmV5akxqS1NoTmw2TXlabU0rb3gybmhkdWoyeVpu?= =?utf-8?B?V0ZUSnAra0Q5L0dqUUJtdUwzQWoyWmp6M1dEbjhIbFFNa1oyVGFPNEtORCti?= =?utf-8?B?RUhYcnNWVGU2a0tucCs4L1BiOStVeVZqTTFBOGRvWDcvRGlNRXNwL0xZYlUr?= =?utf-8?B?OFBzbDQ4SFgwN1doRUNMTFlMSTByaVhIZmdoVXdpekt2dE5RdFN1OVlmMGQ3?= =?utf-8?B?NGM1MXJDYkRNOHAwU2U5azhJNzcrUmlsS1hJbCtJeFcvMjlCcGR0QlNhV3M3?= =?utf-8?B?RzJPc282Z0pPaW4vaXRnSDdOTldMejlGcGpRQXFHYTJzZnBKdCtucmk1M2hW?= =?utf-8?B?eDl5Ym9xZ0tnZ0ZRNUlmcGJIUXdPTXBETGxpWnhYVWU1emtJMjIyMk5VQjdo?= =?utf-8?B?dUdQZ3ZGaXJoTHRuN3lHYkdwcXQ3ZDRueHRPdTVFWjZyUFU0MjBrUXF0R2VI?= =?utf-8?B?VGpvV2x4WWQ5VkVhendka09YY29nVVFQb0hYS2IyNjljdFRZUWZkOHdSUnBs?= =?utf-8?B?bXBjblNwK3RTUW1hcXpQTmozRGNiWkxpcFlFRFVtRVhNRGJoUWRXRzkwbzFp?= =?utf-8?B?ZG1MVW5YTkpReEJMdUJzdFBGNzUrUXM1Q3NCeWNZRGdOK0R2R0pLMjhJdkRv?= =?utf-8?B?YVNUTlVsMG5yWThPU1NtaE1wSDRsRnpHMXZLOExtMEVtd1pKWWd2NzN4WFZn?= =?utf-8?B?L2hqNWhQU2YxYTcvaEFTL3hOVkkrbWtQN0FwSHFuVmpRS3d3NXVXRDZUYmk0?= =?utf-8?B?T20vbUNXVHlKVmJqRFhGZHRKL09ZRVR6dlFHVUUvQ3dYaWdwdm5qWFRxSmM1?= =?utf-8?B?ejVNeVFtSDA4M3lIR2hqOWpRSjZZamNRTGx1V0pzbmxZcE43NUxYenV4ZlJS?= =?utf-8?B?d2lGRmRZR0JBVkFFRFNaUmxiZklRVGIwcnI5ZzUybnQ3eXdLUm53S3Q3OFQr?= =?utf-8?B?RVlGSjZOOTNrNDJudUxsL1RDcXBPeGQ1eWxxclFnTjd3b08xaHlxQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 7dacd265-791f-4be1-e56b-08de9fb62bd3 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:30.2277 (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: ISszC/OuJXGoejoTIkDqA75bB+4zlB5iF2c/EtxVc0MCBWv6JnbBpS/kqiLo0XBdl+hH1exf32UQzDD8aGH2Gg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5674 When a view is narrowed to just a primitive, these functions provide a way to access them using the `IoCapable` trait. This is used to provide `io_read!` and `io_write!` macros, which are generalized version of current `dma_read!` and `dma_write!` macro (that works on `Coherent` only, but not subview of them, or other I/O backends). For DMA coherent objects, `IoCapable` is only implemented for atomically accessible primitives; this is because `read_volatile`/`write_volatile` can behave undesirably for aggregates; LLVM may turn them to multiple instructions to access parts and assemble, or could combine them to a single instruction. The ability to read/write aggregates (when atomicity is of no concern), could be implemented with copying primitives (e.g. memcpy_{from,to}io) in the future. Signed-off-by: Gary Guo Reviewed-by: Andreas Hindborg --- rust/kernel/dma.rs | 46 ++++++++++++++++++++++++++- rust/kernel/io.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 92db0e58f364..d0b86aeebfe2 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -14,7 +14,10 @@ }, error::to_result, fs::file, - io::Io, + io::{ + Io, + IoCapable, // + }, prelude::*, ptr::KnownSize, sync::aref::ARef, @@ -999,6 +1002,47 @@ fn as_ptr(&self) -> *mut Self::Type { } } =20 +/// Implements [`IoCapable`] on `Coherent` for `$ty` using `read_volatile`= and `write_volatile`. +macro_rules! impl_coherent_io_capable { + ($(#[$attr:meta])* $ty:ty) =3D> { + $(#[$attr])* + impl IoCapable<$ty> for Coherent { + #[inline] + unsafe fn io_read(&self, address: *mut $ty) -> $ty { + // SAFETY: + // - By the safety precondition, the address is within bou= nds of the allocation 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 { address.read_volatile() } + } + + #[inline] + unsafe fn io_write(&self, value: $ty, address: *mut $ty) { + // SAFETY: + // - By the safety precondition, the address is within bou= nds of the allocation 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 { address.write_volatile(value) } + } + } + }; +} + +// DMA regions support atomic 8, 16, and 32-bit accesses. +impl_coherent_io_capable!(u8); +impl_coherent_io_capable!(u16); +impl_coherent_io_capable!(u32); +// DMA regions on 64-bit systems also support atomic 64-bit accesses. +impl_coherent_io_capable!( + #[cfg(CONFIG_64BIT)] + u64 +); + impl<'a, B: ?Sized + KnownSize, T: ?Sized> crate::io::View<'a, Coherent= , T> { /// Returns a DMA handle which may be given to the device as the DMA a= ddress base of /// the region. diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 869071d47a13..efcd7e6741d7 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -1009,6 +1009,26 @@ pub fn try_cast(self) -> Result> } } =20 +impl> View<'_, IO, T> { + /// Read from I/O memory. + /// + /// This is only supported on types that is directly supported by `IO`= with [`IoCapable`]. + #[inline] + pub fn read_val(&self) -> T { + // SAFETY: Per type invariant. + unsafe { self.io.io_read(self.ptr) } + } + + /// Write to I/O memory. + /// + /// This is only supported on types that is directly supported by `IO`= with [`IoCapable`]. + #[inline] + pub fn write_val(&self, value: T) { + // SAFETY: Per type invariant. + unsafe { self.io.io_write(value, self.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 @@ -1057,3 +1077,75 @@ macro_rules! io_project { =20 #[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 +/// +/// ``` +/// # use kernel::io::View; +/// 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_project!($io, $($proj)*).read_val() + }; +} + +#[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 +/// +/// ``` +/// # use kernel::io::View; +/// 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_project!($io, $($proj)*).write_val($val) + }; + (@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.51.2 From nobody Wed Jun 17 01:38:28 2026 Received: from LO3P265CU004.outbound.protection.outlook.com (mail-uksouthazon11020131.outbound.protection.outlook.com [52.101.196.131]) (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 DA8E33DA7E2; Tue, 21 Apr 2026 14:56:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.196.131 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783402; cv=fail; b=Xqpea07KO+9sfRHEIGdZ3scBEt3SV3k/TayH0EP87QWgQhuhwlSSqjbT7S76nKAZioF2ABWRh7X/62b7a9Xd+LYo8VrwYnfj4rCEF7PWC34bjpvSR0H239InRnyphilQYBn+ext+ZdSRvXzj4RbHai9HD/L+CL0OocKBT2IkiVY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783402; c=relaxed/simple; bh=PRmb1wvZ+Pmwck3wqC2xoPHaVRyQSptHTYjFPqcyZSo=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=ppl7UhCxeYc5mLcqCBF7+p3Z/CYzhqCkXNT0mfuRPYoFELmegy/d2s1k5axdXT7obNJYP5j3VqEes9Cv1ruzptW23YNURY8QHIWX3y3XPoPZVTWuB54vmlugXnqrKDfp78h0jLnBcfw8bBaPRWhfo9nP1D2nHcKeDe4PoxB2wEE= 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=gzRkEzbu; arc=fail smtp.client-ip=52.101.196.131 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="gzRkEzbu" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=w0fPmim77OhMy/AArBYuqxQN+roqyR9l9RZuxFmzceM4woWHVcpwnUweobxWBpZ27xC/LM0U2LEQ3wYkXgsJqor+OZU5MDtjtsr0VZUylyer/u72k4NZcxxjx6BBhhkRrJUsMfVSxPpawEM7i/v4IKZ/AFkEIZBNYxzIVIozEoJbrZG0XJGvuri3qNoRNCLe+JUOWj6Lf041AMvOnch6ETlBsUxJ54Cs7rGf/nOT749db1JFJ3I4bT48kjxD8/zsvDBtTItg9Sx+trB0oEPSK9DI4DMz+Kz0pYE09KUsnWOAVWGs5WbWBWJaz+EkwJteCb2t/0bBQ4Oa5AnDuo9rLA== 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=ih550/9B0Kfc6sJ+DPgQPhZ40972fjfe4eGDtLBMZLU=; b=QZX9Bk6RFon8KQFFhURnPSRlWLyeMuBeVCRmY3XaU7CIziPmen5+HuW+OQYhz++VBFfjgeUKJTf8Zp0Vki/ZUehgitHdmuaNWuANL2XuG0W3NqLdS7ARt/a+ux4cQFrQGUeaKlvxpeoulmkoAC3IAXnO1XWO62A18Nymd6YUnYgg1atRq9guzN+jM93ufcf/+ZNr3LhjrqHU/q039xJNOljygOqsAHG0urapmNFKDmZY0eyU5eZj16tVAKj5j2y+6vCToJ87N/nVNbrvkQ/AVaNxubkFSaHqipUDuyRHv4TpqV2evS8JpHTfrYbMXVTCc0oamvsbtb73umNwlhDjiQ== 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=ih550/9B0Kfc6sJ+DPgQPhZ40972fjfe4eGDtLBMZLU=; b=gzRkEzbut50jJjaAtXlaQT52b+cu4acFYGMZT0fQ9Cof3hSOVXO9+HuqvCTgD9PV8t+NJZxeloPPVIS4UBRiFpfM6vJq5VT8wxIR+cIW8lTOPugP6ACz2I5X3VtjaxGgtfLq/TOfisp9ZjdlkKbWhM+C1ZOCuvaQD7XTP0oDsQc= 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 CWLP265MB5674.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b0::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.16; Tue, 21 Apr 2026 14:56:30 +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.20.9846.016; Tue, 21 Apr 2026 14:56:30 +0000 From: Gary Guo Date: Tue, 21 Apr 2026 15:56:20 +0100 Subject: [PATCH v2 09/11] gpu: nova-core: use I/O projection for cleaner encapsulation Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-9-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=12845; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=PRmb1wvZ+Pmwck3wqC2xoPHaVRyQSptHTYjFPqcyZSo=; b=FV6fQMw8SBB/uXwMUfB7l1WdZJo0rqbdRde/svIF1wTqDb8Z85lNZJp73GsxFDTvZl3IGtCHr wLXxVRg4vQGDJ5jxA7jGTbfAA6dYLmUsS+8+XnTsMdWcI2Vp7r6Q0Lp X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5674:EE_ X-MS-Office365-Filtering-Correlation-Id: 5c296a16-dfaa-4fd9-dd00-08de9fb62c0d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: pPPf7xu8o1wlcW90ZLLmV7T2nyzZOFxz9kQ0sX6ZolZTDltS0shpan5e83CdWh/rF1Ue7iDW2VnRrefe2wzTgbbzjhG7Y5dtcQLZ0F0GN5CfrKJX/PhibZuJibJ4BcLLIZDJDbiZi/cFLO2WcBY6t043E6UneIRdgaEw2T44afk3eN3ngXpcptUDdZQjEJxsXVYYzHNRu+RjPP161V1yIQh3YCYRxAChcN4HzdJhEWtTDmzJV98VIuD1uLjEBCEf3C0na9Y2eT/C/NMeu1BSG8CQYpxB7UwZ8I/hGpz/mRgtzTtD6wa2KZEEodoBXA7OAN/UbKeFlKl0w3YbByST8LvUCQj1M1JDIE7ibvuMN2HRAk/agq7jYjWvjKb0HXn7myTZWK7WjP9BZFY0Bc50MOY4p+IAF8Nr2Cf4AZkMD6P9SmWkMzdqKwT2kx+IOD5X3USJASxRvzvdyeJprMJpOI1RjCSjdeDq7oKgXID4moWQtujROl3/+QrOlCQb9sFstZM93v4uMcOk6AkPD1xCIFGiRLLeHngGDMfoGDe063PIKSLjfoVtjrmp2L+Essz7rj0cf5LhWOpSjNiZdkpZfNH7u/6DW7JiRtlaCO/ypw8IvtGvwBlBeHL5wLXZJT4GeIAQmp7oYUsSbYqmFWk9HO8eLWkY2XXuvY6R0JHw7Gw1IvFM4kEU6uIqm8ZHDQrWCdDEbs/aIRddxhHx3ckMrQizihEtfWq5R8ZmOJbNiNTt2Ab/A2I2NGK33CouX+FZSvt+7t82u6jEEBp7YGaVHg== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?T1hySG1MUlNDcXlNQVUwdmkzUE5YSGQzajJwdWdvOWs5L3AzQXhkUSs2eTA3?= =?utf-8?B?dVdRSVZwLzNPOU1xZzFkMktqS0ozVnRuZzJYUUVKTldsVXlaUFdMOUtGU1Vn?= =?utf-8?B?MCtUemtYZ2pZc2hUZldMTTVMTU5jdWpPMUpqV1M1aU9ITnE3U2RjcW11WFNE?= =?utf-8?B?V3FGQUtldWRaeFZPaDgydzQ1dHdVVnRMcFhmOHYxKzE5Q2h1a3o3emFOVWw3?= =?utf-8?B?Y3NBbUpQdC9mMWFweWY5RllVTjl6YXN4U01vak0rdm9xRy9RaGNrMDlpbU4v?= =?utf-8?B?MC9TczVHTWFBSHlveTJSOUZ3WERlQnlpaEVaUTJSY3MxVjdlM1llbDNyVDRh?= =?utf-8?B?OUFpb25CNGxFZ0ljeVMxVDVsYjMxZmZuWDJScktGU3pmWU52Ylo2c1J0YjdR?= =?utf-8?B?U2ZMZjd1akRjNE5NcFczM0N1cXk4ckhvSm5OcjhFcmxqN2JzdFlQQmJEOEhv?= =?utf-8?B?cGdReElXWnF6Q1llM25GbjdkczducjhvNlgwMXRSVWVITUErMFhVcnVWNFl6?= =?utf-8?B?RVJ2allKd09XSkk1bjlZMkZPT3hldkZPMUpMQ0pDZEhsaE9ER0lQc3FGa2Y1?= =?utf-8?B?QzVYZVJSTFJuRVhlSkR1YWFQMm44Z2lNcEZHdEw4TXFka3ZOOVF0L1RZcWtV?= =?utf-8?B?OWlLZVh2dWhIcEFVNXh6NGJVdGdqT21wcVlkQ1drYy83eFBGZmd2anhnQ1pJ?= =?utf-8?B?aFlnaFN2VEM0Ti9ieXBhMnZYZnAxQ21nM3diZWNlS2VReHQ0dTJQekRyYU9s?= =?utf-8?B?UVpodjliUytEd0U1NStYWW9yN1hSSzVZeTJlalRhN2JCWDVUWXFudWxBMnlz?= =?utf-8?B?MFArb3lGa1Z2MTdKYkNUQnUrSDI4Q2VndEpRMVJrZDgxcFFMaHh4ajRrbHpF?= =?utf-8?B?ZE16STFBcW1jcWlvbGxwV1NKV3BJcXNpUUg5WHRJODBNa05HSEg4bXRhd0hI?= =?utf-8?B?V2k3MUw2K01JZHppRXk2aHVsNGd4QTFrb3ZuTkFxWkdDeVljTUdHZkx5Yzg0?= =?utf-8?B?RXNZSWRxaWd4YjZFajZ4VGhGdzJEaW83NTdycndGQnBEdVFXUW5wNnRPaW1J?= =?utf-8?B?c1dvd2VMZ0Z1OEYzSWw4UW4rdXo2bDhIVUpXMkpkdXY0UXo3SGMzZlZ3RWk0?= =?utf-8?B?Y3NNazdCZ2FqSkRqZWc1T3Y0RTlUdU1jL1JaVnpwSEhiVTJXeU9LTnBpOExN?= =?utf-8?B?cWg5cTM1V2NzRlo5bTAzUEM3NStwc2NSTjc2V3FldC9VV05hT2NDekkyNGl4?= =?utf-8?B?aFRuUFV6M0p4bE03QkxpaExpQk96cGFrYjJUSENNdkY1WjdoUkVYUmEvNlRp?= =?utf-8?B?WDErNFlUK3JoK2lSTzdoMDNSbFFYb3MzcWUyT3hLT1JHVUJuOW16Wk1DVXRh?= =?utf-8?B?Z2xCOVVhc25hTEdMemdwR0tlSVFuenU0SmJpSUNRZ1BSTXNKeWxhWGdnOGRQ?= =?utf-8?B?ZTE3T09Xb1VXd3kyeG42cUI2a1JkMXp0Y0pxWlY3d1JNNmNDakFKVXIvdnNz?= =?utf-8?B?Qmc2MS9zaVZ6cGtRa0VoYW1YdXVrSU0xd0xjZjJwRXJiaDRCYmRKVWRRU3J1?= =?utf-8?B?cUtrQ0FMUzVKa3ErckRSelVwSHE2aWM0OVBFaTJSSGFXOVZFTjNrT0NlOWxB?= =?utf-8?B?QkM0ZmM1cjk2dG5mazhMWGtyOVcrOTYweCtUQjIzd0pkZkNZMlZIeW15UmFN?= =?utf-8?B?Nk9HaE1MVURrZ0k2V01vUlpTZkFDT1k2dlRNbXM1WDdFRHVDM01hOVRYVC9k?= =?utf-8?B?bStvTDR1d1lhYmp6TUJUb1NVdDlSaFhHOHNRM3hZN25YTEQxUmtjUzVDNzB0?= =?utf-8?B?cmFpWU9ZZWhQRDdzZlM0VlZhSllPZENUZVZMY25sbDN6ME1aV0hyeGN3WWtR?= =?utf-8?B?U05yR0FOVUpWWWc5UmRBMTlHemozM01waVpHQTJYdWoyNWVJdHk4MTkvSDhm?= =?utf-8?B?ZlpTMUdkdTgwb3dxc21VNW83TWNqZTg3Mm9CTnY4NitBUGZMMks5T0pPbVVE?= =?utf-8?B?L2tIRGZoQ2JRV1dKNG9JSU1VOHZGVzdhc2VDKzdEbmdpd09QS2tJSGJTY3Ix?= =?utf-8?B?d2JLdSs2M0VvMDY4VFJ4bXd1dlFOcXd2MTQwUmp4cHB6VUVjN1RjVVlkaEhC?= =?utf-8?B?K2ZqaWhiZ2luYXFza0ptRVNsSldUZS9RMG1wZWpJQ1orcFVJMHhDSDhvSXZt?= =?utf-8?B?R1o4VVpoNTRjRDAreEd3MDJRVHhNRzFhYStrYkc4bzhSMnFLdHYxUVNSOFJU?= =?utf-8?B?eUVHOGczS2MzL2E4akozNndQS0FFY1o0OVdick9aQ0VlK0tSM1pyK01Pdnd6?= =?utf-8?B?YWFFL2NVVW1BQmRnZUhjQUg3Q3lLa0p6YldqcHhIRlVsSXg1NG1lQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 5c296a16-dfaa-4fd9-dd00-08de9fb62c0d X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:30.5875 (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: Gg69nrHXe4QMRqc7yH4sTiMLuBCps5XOEV1dwENujYmYhwC78E5xtjZVSJMtQ2GPyj1qkMRusR2Ckh3s/6G2Aw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5674 Use `io_project!` for PTE array and message queues to remove the break off 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 --- drivers/gpu/nova-core/gsp.rs | 44 +++++++++++--------- drivers/gpu/nova-core/gsp/cmdq.rs | 65 +++++++++++++++++------------- drivers/gpu/nova-core/gsp/fw.rs | 84 +++++++++++++++--------------------= ---- 3 files changed, 94 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index ba5b7f990031..225a77a2f464 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -10,8 +10,14 @@ CoherentBox, DmaAddress, // }, + io::{ + self, + io_project, + io_write, // + }, pci, prelude::*, + ptr::KnownSize, transmute::{ AsBytes, FromBytes, // @@ -55,12 +61,20 @@ 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: io::View<'_, Coherent, 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 @@ -86,18 +100,12 @@ fn new(dev: &device::Device) -> Result<= Self> { let obj =3D Self(Coherent::zeroed(dev, GFP_KERNEL)?); =20 let start_addr =3D obj.0.dma_handle(); - - // 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 0b51e10e2cfc..d424d047c970 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,13 @@ 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 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 + let gsp_mem: Coherent<_> =3D gsp_mem.into(); 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)?); - } - - dma_write!( - gsp_mem, - .cpuq.tx, - MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES) - ); - dma_write!(gsp_mem, .cpuq.rx, MsgqRxHeader::new()); + PteArray::init(io_project!(gsp_mem, .ptes), start)?; =20 Ok(Self(gsp_mem)) } @@ -420,7 +418,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. @@ -429,7 +427,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. @@ -438,12 +436,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. @@ -452,12 +456,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 0c8a74f0e8ac..f2ba2f13e415 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -10,6 +10,11 @@ =20 use kernel::{ dma::Coherent, + io::{ + self, + io_read, + io_write, // + }, prelude::*, ptr::{ Alignable, @@ -40,59 +45,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); @@ -706,6 +658,19 @@ 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: io::View<'_, Cohe= rent, Self>) -> u32 { + io_read!(this, .0.writePtr) + } + + /// Sets the value of the write pointer for this queue. + pub(crate) fn set_write_ptr( + this: io::View<'_, Coherent, Self>, + val: u32, + ) { + io_write!(this, .0.writePtr, val) + } } =20 // SAFETY: Padding is explicit and does not contain uninitialized data. @@ -721,6 +686,19 @@ 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: io::View<'_, Coher= ent, Self>) -> u32 { + io_read!(this, .0.readPtr) + } + + /// Sets the value of the read pointer for this queue. + pub(crate) fn set_read_ptr( + this: io::View<'_, Coherent, Self>, + val: u32, + ) { + io_write!(this, .0.readPtr, val) + } } =20 // SAFETY: Padding is explicit and does not contain uninitialized data. --=20 2.51.2 From nobody Wed Jun 17 01:38:28 2026 Received: from CWXP265CU009.outbound.protection.outlook.com (mail-ukwestazon11021095.outbound.protection.outlook.com [52.101.100.95]) (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 E3A253DB64F; Tue, 21 Apr 2026 14:56:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.100.95 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783404; cv=fail; b=SzoxB1aqBiFCxYIKCtJFd38pd/esNsF22CgOcxgSGS+CNvIRkqJuTprAIS/tc1U9jBce0Txu9nmeuroKweN1imj2RUOml0dQRx/NnP6AbNR5uG2HMSogRtimCZM4WmSk4BqZlc1zEMPOU4rsXyODMjo1at+3VGJhiPXa561yQa0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776783404; c=relaxed/simple; bh=REIYrCsog4jKSossyNrV9NAWmOpEvzTGJMg8c+iA2tw=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=JkZIZgq/YxWtO8bOMiw5TtzoKca1bnnMMcYzggefU1FmlIqqZq82t1wNZm82H6DQHHs2/WpK2NWUPN1WJbBj4F+Ep0dm9Ps0/mmucDDUO8p1ojukKxnfPFxd3C4cktOYPK974g/B1lQ8XIGsQ67gnHQiXbWM1k9lPczVCHDaqTI= 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=uDjVdfSu; arc=fail smtp.client-ip=52.101.100.95 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="uDjVdfSu" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=KKZiEYpepveV1NDs+cVzuz8AVkf8f0HKM9cr0WYQe6XoX2dVLL5DxeaEkBs94n7diPS/ghWZMcuvc3+w2uRv71fu2L7hTW6id4cNroH17e81QHpKNy95MOWIy2AKpP5T186Z4zU78R43hAOq/Rv5zYZhYZ06bJchWDSAawn2T2WSlvgKfn06UlKigecHu9fv/AKFbGWGOB0dgZbaURv7OlTyoQfGmwc9sZ1GlaOyDSidw8ySQhNtd/jTX7GwEBWdazsgs71R8cWMkUchxRvBgZX1V/M7JcvcPrpEyrSb6igxT2jBk/kvMdn8fYfsAg+Kpqy8N/dNCFxyHpZEsTfTTQ== 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=cOPnJ8/rArX21QGk5WpOti5jc4cbsiKxm9EchkvMApg=; b=xCjbr0BH7q2pxuoKfDVGvvaO4pG3b4B/2uIzlZWRxJdnouCuuwdOo398n+7udeBpDUw4VB1MmwlYiF6+tbfKnWgHwDZEG1OySt/TmiaZxYoK8Q29Jzilk0jGZASOvRdKws3Z3zY1NbzzG8krknHdZpc6aUsHA78mV97CFfFzAktzBqR03RpTvfKXyUsRCf7EPW7j4bYXhMP+tsIP4WZY/ZCyKQQ702i+bsM7m3ONbx10enCpsyY3wNpKlKK6CpQMSkUQleTOmOu2jZUwsHqr6TDV3AT63MdG48LdprMSLcMCzk6Rx1yo1HLDxCGQ7Gr+L654HxH5TJ3hAPHHK9RdDA== 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=cOPnJ8/rArX21QGk5WpOti5jc4cbsiKxm9EchkvMApg=; b=uDjVdfSu6sOy7Mxzgg08DYLOsQVvW2hFV090Tim7j85NWuHNw89g6XH2loEZLmJTIx2g25OvRVqvG42+5OoK6cbC2azd4nybNJ0g9ZhNk2cELkXMhLrQLXRHlyNLmkgtaWhPZtDD5ph/6QdbxUwyszvRJVQ29FfyAsNxBA33Be4= 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 CWLP265MB5674.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:1b0::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.16; Tue, 21 Apr 2026 14:56:31 +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.20.9846.016; Tue, 21 Apr 2026 14:56:31 +0000 From: Gary Guo Date: Tue, 21 Apr 2026 15:56:21 +0100 Subject: [PATCH v2 10/11] rust: dma: drop `dma_read!` and `dma_write!` API Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-10-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=9221; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=REIYrCsog4jKSossyNrV9NAWmOpEvzTGJMg8c+iA2tw=; b=LuAgQuSw8Ou9slF2iDjHLVQajkitMXsFiUlYzh8tm0bNggeeRvCe9j6sgAMxSZI2tQ70fU6/I Kl0lp6+kd1hADXhZ9bhgcMAuElCCQmegjdzjKzdxGNUMrRSZfkSLH95 X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5674:EE_ X-MS-Office365-Filtering-Correlation-Id: 1f06d217-a096-40be-f5f0-08de9fb62c4b X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: 5ocNZWZgcd37BmPL0woIBLIYT+mV+v++X3PLhzEdBAE95vJaqoUde/DHDg6WCV3kjwv7Z2dkofOM8QkyIQvxshgALD2+Nw3B5yMMOYxRaxanMaFNqetzBBQ4lkJkctTaB6A11hZpNioR0LtbnDorLWhv1HD+0nlVYWSZw3A/SKsfYBdaBjZfNzlBED2c/Ht2cdnmhUc7Ux79k7DZb3H+zXcKoIui7yW2fTjNpJFpqFAPvWgGTwv5bJOi/ajvKnblvTSwhXU8MgySO/LV14aK8ottnHElYdwNdfnQyjSg2vG37YVr1xpCl4ciN7UBb8nWGV4wyC7EBdHGN4ZY5ljnPT3BJmJKThLWoNbbBaACBV8dS4Ozk/lcgVo9kOFWsHowQR5ITrIqEV/svpqmWaaHSAaTAJ5h7UBOb7w08ZbX8Utg5clSYSYYquh37fOWJfbf3O1BfQYFV7XNz0weDTo5y93Cb2yw6QVzxsMLxfBp+QymTDfPhLzS3vxbzYWSerkrh6gpYzWgXgUoySSEht+Pd7gOiYtzkSEhGUmK37mn2t/lh2gZON58uSbspF3nTOBAnpwZk54FI3CCQJbO6MefAm530Ff6X2nJW6IETg856MRFq3xrO7wlMhQseS9LuQp0c1MKnD1Cf9dbBzke1D81srxjiOR/1mhJdsJTK2yDCm5+1o4PcH+x/XSX911sLIz1frRKkoFXQeEKqoJLa8OstpS4pXt8t2/xNh/384XFNtjHREfMFTNO+vJHxMA4SK+T6Nio+7cFRtk0jBf7/4fhdA== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?M1E5eUkvWlVjM0p2ZjRxOFdBenh2eUtsL3BWTUtWK0VvMU9Qci9Yb1JRNVhR?= =?utf-8?B?enZPTHp5dkNxQ3lPaG1oTEVzcEpGb29Kb0gyZ1ptK250ek1ZbE9qdG9rdHA0?= =?utf-8?B?UjREMmZ4KzRVSWJ0TmE4LzZNMXdzZUEvTU9sZ1VKVDNBRTA4MW1vWkNtRk9z?= =?utf-8?B?SnlRMnkyZDVad3RFb256RVREek9CYm9IVE5ZcDFmSm1yakUvV3pFMGIrMTZj?= =?utf-8?B?YW1ZWndtRnZjdks0Uk9xMmhHRmZIZFRnemZuNytvbkJORnJjQkIySmZvcTdS?= =?utf-8?B?UklkTjFaZXUrSVB0anBhTFJPbmYra3lHNmlpdmdWUFRrVno5Yk9ycGhlYzVX?= =?utf-8?B?S0FlbWhTVWRTbGE2QWNxR2p2cXg3TFBvUUVKSFBxSW5GMnpldWZyc3Vqb1Fo?= =?utf-8?B?bGlVWmpoTHpqclhIMkRwY1l2REJrS2Y0Z1paNnhKS0tQUkZWR3VBZUEzd3RC?= =?utf-8?B?SG1LVEpOaXUvdnpBL1pHNS9qdDN3dWNZZCsrcEVOZWh4SUE2TDN3M3BXb0Y2?= =?utf-8?B?aDEyREdaS0xRc2RuVVVMZ2Q3Tlg2ejEvZlg2NU9LOGZQZlgvSVpCTUtMWkla?= =?utf-8?B?dEoyUEpHK2JNSkZmR1YrOHpJNWliYncyRHFLQjNWaTIxR3U0TVhjOWpiTzBv?= =?utf-8?B?Rnhhc2gwSFUzWmdOWWQxZ0diMlBES2VwdS8vMTJDYXhrak40L2o4cC96Sjly?= =?utf-8?B?TXNqK09JVWk5VWpQRFFaNmVaT2EvOEh5ek5KaG1hZVcrck1CdmdhYWJMSjZP?= =?utf-8?B?aGtvendWeHY4cm9nb1lPM1RyZndyZEZPRE9tY2NJTFVIQWhXSFAvM3ZpUE5x?= =?utf-8?B?TGVVcTdsbzNuV2VrQTNpbk4wZEp2aWVtZmxKaEZNc25ZTTVYQVkrNE5VSTNa?= =?utf-8?B?RHlIRkJQQTgweFNqcXZNUWhDb2UyL0xJRWtOWEltS1VRRTVNZnFSVDh0a09F?= =?utf-8?B?M2tYQXAzT2lZZjZCL1ZEQ3ZmSWRiTDZhMCtkQnEwSDY4UDVuYU5pcmh1MlBK?= =?utf-8?B?czNySGRCTVpBbnMrOHR5Um42cXI1emhrMkxLWXdvN3F6UEg4NXpzZC9wNUZq?= =?utf-8?B?blNEWW1DZEdUN3dLOFM0dmhPMkRYby92amtudWVtd0NzMWJpcGttNWRZYjEy?= =?utf-8?B?dWNLSlVSUHdxR0pRb21FdHlhSW5GdGl0VlZHSkVmMmYzQkZoNzlsZmQ3NGpI?= =?utf-8?B?R0F5Y1lrMmp3aWV5YW5oSEJzaTFKcWQwSXMvNGZ4UjVaNThLeUkzVlJMdU44?= =?utf-8?B?R3Fzc3J6bEd5OExUYWl3V2h2L21vSWZHbytELzlzNy9MVWsrN0hSeFZsT3kz?= =?utf-8?B?dWJFK2twQlRDUDc1Z2d2cFBCME9zRG9mdXBBUU52VFhEOXF3cVZZS3hLU3VO?= =?utf-8?B?alNlczNKM1g1Z2VrU1RhSEk4Y0xqdUgwRGdqMEZMdHdFd2ttT2dUaHdLMFMv?= =?utf-8?B?a2s0SzlxWFIyWFQ0bEZXaHNkaUEzclJrbnNLbjJxeXFyM0lHb2FCdDRUU09W?= =?utf-8?B?YXdaOXdXRHBseEhuZWM5YkZxSkRpaytJSDY2Q3dQd1BSY2xXNEVDWHZBWHRo?= =?utf-8?B?aGZLbkNIeldxUk54Sm80eG51VlRoUEZENnNLOENneDhHckZ5dVV6dmRhVFl6?= =?utf-8?B?b25XRk51ZDkzLzVERHJpa0xadHBGSko1bWxMSHQwdzlNVWZiZGdma3hnVngw?= =?utf-8?B?NHlVNmxvOG1jTjdyV1dnQVJzQ1QyUm1UMkR0ZU5hNGUxWlUrNHJQVjNlU0Jk?= =?utf-8?B?YWpUTVZoWmFqcy9vMVd2ZWU2aUt0STVnTnptWUNUa0VxUVdpTDhCVFRyaXB0?= =?utf-8?B?TTlxZGdCK0ZnZ3JWTW9rYkNYdnVhNW83Y294Tm95VElqK0FXc3duSS82Vms5?= =?utf-8?B?Wis1RkpBb1ArQmxvdTNpRE1aQ3VsN1p1cVRXbnptSG4rSUhmd2FPMXR3NURC?= =?utf-8?B?SUdmdGJ2TTRla2Y4bVo5QTlrNWttN0hzSlZUd3ptY3YzVk4vemtFNTlBdUR1?= =?utf-8?B?RWdJa1ZtNGR2cFhXc0pwL1hJWHB6d0V4a3hUKzdYUlJQN0xXa3YveDl1ekt5?= =?utf-8?B?NGNPSGZBTndNeUt5M3JRREpmNFNZaXptWGJNdjFpNGVyZW9odm9Nc2k5eTZm?= =?utf-8?B?ZnBVejNtUEZleGhaYS9SM1AwdW5ObnV6bFltSCtFWHdFTW1KR2VKYWduQ2RJ?= =?utf-8?B?OEw5MEphZlo3QUJoOTVFRFFxWDc2dkFyWXR1SGFjeS9hdzdPOW1ZZGxYa2RO?= =?utf-8?B?cUg2Rm9FdEdXY0Q0aTltVVBEc1Brb0NJNFZpT2NYMkpUMEttdUtMNVJoY3Ba?= =?utf-8?B?K3lPbXJZVi93Q0RLQjBPQ0NDWVRJT0pSeFRtZmpOUFBRM09XNUo4QT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 1f06d217-a096-40be-f5f0-08de9fb62c4b X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:31.0027 (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: fvm+s4jTJs/7Y5L7YSN3N3hy0iD0ZUw4ienwhPt+01g8XWpZXbM+NHOei5q/S0pHJwDR0nvG8ViwbJh4md/AUQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5674 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. Signed-off-by: Gary Guo Reviewed-by: Andreas Hindborg --- rust/kernel/dma.rs | 128 -------------------------------------------= ---- samples/rust/rust_dma.rs | 14 +++--- 2 files changed, 8 insertions(+), 134 deletions(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index d0b86aeebfe2..bbdeb117c145 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -658,52 +658,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 { @@ -1230,85 +1184,3 @@ unsafe impl Send for CoherentHandle {} // operations on `&CoherentHandle` are reading the DMA handle and size, bo= th of which are // plain `Copy` values. unsafe impl Sync for CoherentHandle {} - -/// 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 a2c34bb74273..9250ed6f6673 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -8,10 +8,12 @@ device::Core, dma::{ Coherent, + CoherentBox, DataDirection, Device, DmaMask, // }, + io::io_read, page, pci, prelude::*, scatterlist::{Owned, SGTable}, @@ -69,11 +71,11 @@ fn probe(pdev: &pci::Device, _info: &Self::IdInfo= ) -> impl PinInit =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; @@ -83,7 +85,7 @@ fn probe(pdev: &pci::Device, _info: &Self::IdInfo) = -> impl PinInit, _info: &Self::IdInfo) = -> impl PinInit Date: Tue, 21 Apr 2026 15:56:22 +0100 Subject: [PATCH v2 11/11] rust: io: add copying methods Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-io_projection-v2-11-4c251c692ef4@garyguo.net> References: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> In-Reply-To: <20260421-io_projection-v2-0-4c251c692ef4@garyguo.net> To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Daniel Almeida , 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, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1776783386; l=11952; i=gary@garyguo.net; s=20221204; h=from:subject:message-id; bh=ERQyRg6FCVwG0U5GQXUSxvKmT2yPSztVRq39JXT1JUo=; b=uV59Tig1UAY86hboNAV4E3WIfI7Ql+9hlbKVgSxDejiR22aUNKPgwm2L01kkGD4YuxBthGXxB VK9/9YS3bVzBoD0RYoIqOm+9CZIpiMdSTwrbXneIfGvR8KxGbIJFG8S X-Developer-Key: i=gary@garyguo.net; a=ed25519; pk=vB3uIX95SM4eVrIqo1DWNWKDKD2xzB+yLLLr0yOPYMo= X-ClientProxiedBy: LO4P123CA0142.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:193::21) 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_|CWLP265MB5674:EE_ X-MS-Office365-Filtering-Correlation-Id: 85b87724-6a5a-469a-3a8f-08de9fb62c86 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|10070799003|366016|921020|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: orwlKEzGLNpwUFSx1iOk6ddBcck9W+HB7LIjcjLuWtfGqqO5Q7MN9w8ErEBMiQFEzbQMNLz35LfgfaYZ0hD4A9YrxjdPSCOfBFe9QsTI9PQhGT91T2b49Z82HrMQiZmL4i6h15hl1wOFrZNMhUaxTRYV8tsjhfHJXa1jRi+boIVrdcHh4lUQvwgxB+laWqxUsO3ceSmDpYl7NnJZx2hEBa4azfuIVqhrTsCxWw2IVIHYCHW5hU6CQY1RRNtD17iF12NMCrtJkvThkiJzUodaSVZzfSW2kMntRfkqIerqgNrCXqO+/g95l9gQlj0p4aBeT+I7y64CGFWoWSRif5JEo/yiUmzFLEB1XNIGyb3xsa9R0KZktAj01IRpOxWGTcyCTFmP7bvjTSnf+SXRjJtivvt40cvqW0ystH6SfTGEmHirS9jPt1BTmwG+sLeGS0/JZcRHdZWuTmh6q4fpRyTQrrOzgj/kuX5VTvb16mt3yg88HdZ4fmVBYvVB0zW4jD1wMVhwhBgrPj8j26joS+O6vt6IkhRtwVp+yNG153fHV1pb2RSU9KFLQlRss4MdNIFiK5BDpfGrHTtbZrNgOetI8VjUX7hrzW6rEw8b2ifVrjUlMWM94TWeDyOGLQRWzU17uxX8Z8KkzIBBA9aOhymiEDIyYlIfefufa2ZiQl6qW3prPsx3jwhB4cFxLlueD675eZLhWGJPIajTNH1n4rlKgebKzV3UV/lAN1MSPHx/jQtYfVkfJIjf80+qS/gPM+nLySDmnS4vPTZHTfohhMr+8g== 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)(376014)(7416014)(10070799003)(366016)(921020)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?L2wzS2RSTTFsSEQrRkxmWVB5anJvL3I3Q0F4emg5a3JFZDl4Nnl4RVhSUnpW?= =?utf-8?B?bUg4S0d0YjJMMm9wM0NoZ1Q2ZnZ3L1ljZjNrVnBQWDVzR2NCK3ExYTZ5NmZO?= =?utf-8?B?NUlKMFpMVE1OOW5VblBKMGFLa09iV0c3OE9LdVluYUtFOWxtamtWdWhxcFM3?= =?utf-8?B?TDNmNzA0VG43bmxDelZjdk9CcUEwZU04eVFPa1I2V3NtWEVDbXJxSEpybFlr?= =?utf-8?B?dDEzenh4ZUZSeHpxQzZ0dFFrYnNtMzNNeFc0T3BGaWRDWWFGYlZyTlpsY0hq?= =?utf-8?B?bkxCeURVLzgyYTRmZHhjVFJpVnQwNDRGdUo1dzMwZDZVREhibjcrUTRnT1FS?= =?utf-8?B?Q1hMdmtXTVdGeGkzVFprekVRalR1eUsrWmdocWY1RXZnUjR3U3phYkZBL3B2?= =?utf-8?B?cVNRQ3htUUdTNy9mckFiV3NXWDlabDZzejdBZk1MTGVEdkxrWUdHWWcxT1k3?= =?utf-8?B?Sm9YN3lvYS9tS04wUlRqTjd3UkhyYkZtWVZqdnMrTGRRVmt0TmhpcVNiWXAz?= =?utf-8?B?Vk95NlNFK0Y5NDlLVUFrVlE3MXZlWjdSc1FYZ0t3cVBJUEpjZ2N6YzdUT09M?= =?utf-8?B?WW5vNTNSTlg3MnBOWWtIZGlNY043cVpxSndGK0pQMGdSTytxNjU4U0YxcDBJ?= =?utf-8?B?VGQ5RDNtelU3WlM2OUhLU0QxSUJGaVo3SklvNk14bkVjNUVKNjZKaU84ZzdD?= =?utf-8?B?eHV4NzAyR3RrcS8weERya2ExdGxGY21rSE14VUwzYWgrVFpLU2J3cEkxcHRw?= =?utf-8?B?R1p1eXd0ZmduL2FGSjRBWWtzWkhTTHlZNi84MFhXQ1JDTXZrNHQ2M3RoL0I2?= =?utf-8?B?REZZeGFla0IzbERhQjlqS0QzUlJiUkk0ekhNY2ZIVUdJMXByZ0tTcmFFUkE1?= =?utf-8?B?Y3dwOUVnRWVrSG1CRWdMcHhxTWNFM0hBbjliY0NieTJwYjU4MjdyakhzR1RV?= =?utf-8?B?dzhqYTcrNktwWVh6YzdHRktKRVlXVWhGM0ZEVWZhOXJkM1VMM0NRcTBTNTRw?= =?utf-8?B?elRNN21xTTlLbDNSaHhvdTBiZENrNWpybXdPbENhZzFmY1ZteUlDOXhabjc4?= =?utf-8?B?dnZzbW5Bd1RrV2M0SldGS2NjRGdWb3lyYUFEdUNycTN3MUtvZ1A5b3V0MjRa?= =?utf-8?B?Uk5wMG9hVDVEWTl3VFhML1dXWXhoZmtWYmkxTWsrUlR0Nyt1R0Q2N0RvTEh6?= =?utf-8?B?c1dHaUlBaXplai9vMGZlVGxKcFNEZzBVbXVCMmlFRUZtU3JsQk13dUJxK2w0?= =?utf-8?B?NnRBU2NUeTlGM2JLVWxpQlpWbUVxZTIvT1d3K2U4M1dUZjd6bVNlR25BNmxr?= =?utf-8?B?bmdhRnNMcGJyQWpZcjVMMkdNUnRtTEF2VFpnNDFyM2lpTjE5Z3VhajRaVUdT?= =?utf-8?B?dTAzWjR2cW56WkpIUHYzNmM1ZnV1blBvdDJkTUljU1lzeU5hSkhVajZGdThx?= =?utf-8?B?TVYxQXF4M3RyNElWMzF6MGFsMUJSTVo1QmxUWjNCNGRjUjFhNlRGL0JCam5P?= =?utf-8?B?THhOVHhZQXRzU080Q3hweFhkeE0zSFgvejNQQ3JWUDc3TjhOU09VcTVXdHk2?= =?utf-8?B?andGSGFpODYrblFjZWQvYTRTWDk0ZjYrcWgrNXVaRis5RzhQS0xJSUdrUkEw?= =?utf-8?B?NVl0VytHRWxnWXBrNzE4Y1Q4MGNJSGRGYVlmOHFvWDBXMUlIUnl6ZDFMSkhu?= =?utf-8?B?WnFETk5wUGJHNkRSRzJHVFJZRHlQRHVDNTRqekFLNWpFeHg5RUNHVk1meXFT?= =?utf-8?B?bFNzMk1Eb1VvU0RNVm8rUXJ1ZSt3d1FCK281ekRCZ0FqOXhoK1hxTTN4dXNs?= =?utf-8?B?NHR2aDFSbDJLekx5NG1PMXFoU1B0NDB1dEJjakNNK25yaFdsRUtGN2gwdERT?= =?utf-8?B?ZDlIV09Sa2M5R1YzZXA5enNsZTEvS1IrdzBJQlpKY2FEcjFKVXA5NkxpOVpv?= =?utf-8?B?LzRQUTY1MHd1akFnUTBrT3l1QlRibG5jLzlQd2FDR2RnUDlReiszd3ovZmEw?= =?utf-8?B?YXgzODZMZTNNWjhDRnIxellsMTZFcmZ5VmdZOEFSazVkbGRpMjJEekdvbUQ3?= =?utf-8?B?K0tZeUZJM1Qvdmk0VDEyRUlqQW54NTV1Q2FSUEtPK2hhdXVJaEorYWs5a1VF?= =?utf-8?B?emVIT2hkbGpiTU95VllManlLNWQyMklvSVR3UkpxQ0VYcG1iRnpsd3hLZWZk?= =?utf-8?B?MGhiUWd3eVUybUtRVlBETkhCVGw5VHB6WExXNHlja3dGUkN4T1lVT2JBam9k?= =?utf-8?B?SWZHT1dncW1FVjhsR2dmVldMNjd5WSs0UFovZEQraEhsa2NRVElDQW1wVW1Y?= =?utf-8?B?VEF1cVdKMGJqSHFEUGNqdXZhUXd1ejZEaDNYUWxOeDBxQ211Y1pyQT09?= X-OriginatorOrg: garyguo.net X-MS-Exchange-CrossTenant-Network-Message-Id: 85b87724-6a5a-469a-3a8f-08de9fb62c86 X-MS-Exchange-CrossTenant-AuthSource: LOVP265MB8871.GBRP265.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2026 14:56:31.3720 (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: 3LV5lvyij58RXqf6uE0dooijMGQBJkU4DWKi7/H4dSu/JMv9ySwnImpIZCXowG/b9jW5oLzyb5xOpT7WvmVjJg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CWLP265MB5674 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-introduces 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) The semantics for these are modelled 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, which maps to `memcpy_{from,to}io`. For slices, which is unsized so the API above can't work, `copy_from_slice` and `copy_to_slice` were added to copy from/to normal memory, and `copy_from_io_slice` and `copy_to_io_slice` were added 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 --- rust/kernel/dma.rs | 8 +- rust/kernel/io.rs | 231 +++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 238 insertions(+), 1 deletion(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index bbdeb117c145..307f5769ca0a 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -16,7 +16,8 @@ fs::file, io::{ Io, - IoCapable, // + IoCapable, + IoCopyable, // }, prelude::*, ptr::KnownSize, @@ -997,6 +998,11 @@ unsafe fn io_write(&self, value: $ty, address: *mut $t= y) { u64 ); =20 +// SAFETY: `Coherent` is mapped to CPU address space. +unsafe impl IoCopyable for Coherent { + const IS_MAPPED: bool =3D true; +} + impl<'a, B: ?Sized + KnownSize, T: ?Sized> crate::io::View<'a, Coherent= , T> { /// Returns a DMA handle which may be given to the device as the DMA a= ddress base of /// the region. diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index efcd7e6741d7..0b1ed68c0f9b 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -4,6 +4,8 @@ //! //! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.= h) =20 +use core::mem::MaybeUninit; + use crate::{ bindings, prelude::*, @@ -233,6 +235,55 @@ pub trait IoCapable { unsafe fn io_write(&self, value: T, address: *mut T); } =20 +/// Trait indicating that an I/O backend supports memory copy operations. +/// +/// # Safety +/// +/// If [`IS_MAPPED`] is overridden to true, it must be correct per documen= tation. +pub unsafe trait IoCopyable { + /// Whether the pointers for this I/O backend are in the CPU address s= pace, and are coherently + /// mapped. + /// + /// When this is true, it means that memory can be accessed with byte-= wise atomic memory copy. + const IS_MAPPED: bool =3D false; + + /// Copy `size` bytes from `address` to `buffer`. + /// + /// # Safety + /// + /// - The range `[address..address + size]` must be within the bounds = of `Self`. + /// - `buffer` is valid for write for `size` bytes. + #[inline] + unsafe fn copy_from_io(&self, address: *mut u8, buffer: *mut u8, size:= usize) { + const_assert!(Self::IS_MAPPED); + + // Use `bindings::memcpy` instead of copy_nonoverlapping for volat= ile. + // SAFETY: + // - `buffer` is valid for write for `size` bytes. + // - `IS_MAPPED` guarantees `address` is in CPU address space, wit= h safety requirements + // `address` is valid for read for `size` bytes. + unsafe { bindings::memcpy(buffer.cast(), address.cast(), size) }; + } + + /// Copy `size` bytes from `buffer` to `address`. + /// + /// # Safety + /// + /// - The range `[address..address + size]` must be within the bounds = of `Self`. + /// - `buffer` is valid for read for `size` bytes. + #[inline] + unsafe fn copy_to_io(&self, address: *mut u8, buffer: *const u8, size:= usize) { + const_assert!(Self::IS_MAPPED); + + // Use `bindings::memcpy` instead of copy_nonoverlapping for volat= ile. + // SAFETY: + // - `IS_MAPPED` guarantees `address` is in CPU address space, wit= h safety requirements + // `address` is valid for write for `size` bytes. + // - `buffer` is valid for read for `size` bytes. + unsafe { bindings::memcpy(address.cast(), buffer.cast(), size) }; + } +} + /// Describes a given I/O location: its offset, width, and type to convert= the raw value from and /// into. /// @@ -841,6 +892,19 @@ unsafe fn io_write(&self, value: $ty, address: *mut $t= y) { writeq ); =20 +// SAFETY: `IS_MAPPED` is not overridden. +unsafe impl IoCopyable for Mmio { + unsafe fn copy_from_io(&self, address: *mut u8, buffer: *mut u8, size:= usize) { + // SAFETY: Per safety requirement. + unsafe { bindings::memcpy_fromio(buffer.cast(), address.cast(), si= ze) }; + } + + unsafe fn copy_to_io(&self, address: *mut u8, buffer: *const u8, size:= usize) { + // SAFETY: Per safety requirement. + unsafe { bindings::memcpy_toio(address.cast(), buffer.cast(), size= ) }; + } +} + impl Io for Mmio { type Type =3D T; =20 @@ -1029,6 +1093,173 @@ pub fn write_val(&self, value: T) { } } =20 +impl<'a, IO: ?Sized, T> View<'a, IO, [T]> { + /// Returns the length of the slice in number of elements. + #[inline] + pub fn len(self) -> usize { + self.as_ptr().len() + } + + /// Returns `true` if the slice has a length of 0. + #[inline] + pub fn is_empty(self) -> bool { + self.len() =3D=3D 0 + } +} + +impl View<'_, IO, T> { + /// Copy-read from I/O memory. + /// + /// There is no atomicity gurantee. + #[inline] + pub fn copy_read(self) -> T + where + T: FromBytes, + { + // Optimized path if I/O backend is CPU mapped. + if IO::IS_MAPPED { + // SAFETY: + // - `IS_MAPPED` guarantees `self.ptr` is in CPU address space= , with type invariants + // `self.ptr` is valid for read for `size` bytes. + // - `T: FromBytes` guarantee that all bit patterns are valid. + // - 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 { self.ptr.read_volatile() }; + } + + let mut buf =3D MaybeUninit::::uninit(); + // SAFETY: + // - Per type invariants. + // - `buf.as_mut_ptr()` is valid for write for `size_of::()` by= tes. + unsafe { + self.io + .copy_from_io(self.ptr.cast(), buf.as_mut_ptr().cast(), si= ze_of::()) + }; + // SAFETY: T: FromBytes` guarantee that all bit patterns are valid. + unsafe { buf.assume_init() } + } + + /// Write to I/O memory. + /// + /// There is no atomicity gurantee. + #[inline] + pub fn copy_write(self, value: T) + where + T: AsBytes, + { + // Optimized path if I/O backend is CPU mapped. + if IO::IS_MAPPED { + // SAFETY: + // - `IS_MAPPED` guarantees `self.ptr` is in CPU address space= , with safety requirements + // `self.ptr` is valid for write for `size` bytes. + // - 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 { self.ptr.write_volatile(value) }; + return; + } + + // SAFETY: + // - Per type invariants. + // - `&raw const value` is valid for read for `size_of::()` byt= es. + unsafe { + self.io + .copy_to_io(self.ptr.cast(), (&raw const value).cast(), si= ze_of::()) + }; + core::mem::forget(value); + } +} + +impl View<'_, IO, [u8]> { + /// Copy bytes from slice to I/O memory. + #[inline] + pub fn copy_from_slice(self, data: &[u8]) { + assert_eq!(self.len(), data.len()); + + // SAFETY: + // - Per type invariants. + // - `data.as_ptr()` is valid for read for `data.len()` bytes. + unsafe { + self.io + .copy_to_io(self.ptr.cast(), data.as_ptr(), data.len()) + } + } + + /// Copy bytes from I/O memory to slice. + #[inline] + pub fn copy_to_slice(self, data: &mut [u8]) { + assert_eq!(self.len(), data.len()); + + // SAFETY: + // - Per type invariants. + // - `data.as_mut_ptr()` is valid for write for `data.len()` bytes. + unsafe { + self.io + .copy_from_io(self.ptr.cast(), data.as_mut_ptr(), data.len= ()) + } + } + + fn copy_from_io_slice_via_buffer(&self, d= ata: View<'_, T, [u8]>) { + let mut buf =3D MaybeUninit::<[u8; 256]>::uninit(); + + let mut dst_ptr =3D self.ptr.cast::(); + let mut src_ptr =3D data.ptr.cast::(); + let mut len =3D self.len(); + + while len !=3D 0 { + let copy_len =3D core::cmp::min(len, 256); + // SAFETY: + // - `src_ptr` is valid for I/O read of `copy_len` bytes per t= ype invariants of `data`. + // - `buf.as_mut_ptr()` is valid for write for `copy_len` byte= s as `copy_len <=3D 256`. + unsafe { + data.io + .copy_from_io(src_ptr, buf.as_mut_ptr().cast(), copy_l= en) + }; + + // SAFETY: + // - `dst_ptr` is valid for I/O write of `copy_len` bytes per = type invariants of `self`. + // - `buf.as_mut_ptr()` is valid for write for `copy_len` byte= s as `copy_len <=3D 256`. + unsafe { self.io.copy_to_io(dst_ptr, buf.as_ptr().cast(), copy= _len) }; + + dst_ptr =3D dst_ptr.wrapping_add(copy_len); + src_ptr =3D src_ptr.wrapping_add(copy_len); + len -=3D copy_len; + } + } + + /// Copy bytes from `data` I/O slice to the `self` I/O slice. + pub fn copy_from_io_slice(&self, data: Vi= ew<'_, T, [u8]>) { + assert_eq!(self.len(), data.len()); + + if T::IS_MAPPED { + // SAFETY: + // - Per type invariants. + // - `data.as_ptr()` is valid for read for `data.len()` bytes. + unsafe { + self.io + .copy_to_io(self.ptr.cast(), data.as_ptr().cast(), dat= a.len()) + } + } else if IO::IS_MAPPED { + // SAFETY: + // - Per type invariants. + // - `self.as_ptr()` is valid for write for `self.len()` bytes. + unsafe { + data.io + .copy_from_io(data.ptr.cast(), self.as_ptr().cast(), s= elf.len()) + } + } else { + self.copy_from_io_slice_via_buffer(data) + } + } + + /// Copy bytes from `self` I/O slice to the `data` I/O slice. + #[inline] + pub fn copy_to_io_slice(self, data: View<= '_, T, [u8]>) { + data.copy_from_io_slice(self) + } +} + /// 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 --=20 2.51.2