{"id":2220217,"url":"http://patchwork.ozlabs.org/api/patches/2220217/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-pci/patch/20260406165120.166928-5-wenzhaoliao@ruc.edu.cn/","project":{"id":28,"url":"http://patchwork.ozlabs.org/api/projects/28/?format=json","name":"Linux PCI development","link_name":"linux-pci","list_id":"linux-pci.vger.kernel.org","list_email":"linux-pci@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260406165120.166928-5-wenzhaoliao@ruc.edu.cn>","list_archive_url":null,"date":"2026-04-06T16:51:18","name":"[RFC,v3,4/6] rust: pci: add shared BAR memremap support","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"212c65e2085378f83203ee8d5cdb665c8cd48333","submitter":{"id":93071,"url":"http://patchwork.ozlabs.org/api/people/93071/?format=json","name":"Wenzhao Liao","email":"wenzhaoliao@ruc.edu.cn"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-pci/patch/20260406165120.166928-5-wenzhaoliao@ruc.edu.cn/mbox/","series":[{"id":498880,"url":"http://patchwork.ozlabs.org/api/series/498880/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-pci/list/?series=498880","date":"2026-04-06T16:51:15","name":"Rust goldfish_address_space driver (ioctl-only subset)","version":3,"mbox":"http://patchwork.ozlabs.org/series/498880/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2220217/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2220217/checks/","tags":{},"related":[],"headers":{"Return-Path":"\n <linux-pci+bounces-51969-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-pci@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=ruc.edu.cn header.i=@ruc.edu.cn header.a=rsa-sha256\n header.s=default header.b=OIBZWDGJ;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-pci+bounces-51969-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (1024-bit key) header.d=ruc.edu.cn header.i=@ruc.edu.cn\n header.b=\"OIBZWDGJ\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=47.88.81.201","smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=ruc.edu.cn","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=ruc.edu.cn"],"Received":["from sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fqFqm4PgXz1xy1\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 07 Apr 2026 02:57:24 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 76EBB30166CB\n\tfor <incoming@patchwork.ozlabs.org>; Mon,  6 Apr 2026 16:57:04 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id A153C38B7D7;\n\tMon,  6 Apr 2026 16:57:03 +0000 (UTC)","from mail-m81201.netease.com (mail-m81201.netease.com\n [47.88.81.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 59EC431985C;\n\tMon,  6 Apr 2026 16:56:58 +0000 (UTC)","from lwz.tail698a0e.ts.net\n (gy-adaptive-ssl-proxy-1-entmail-virt204.gy.ntes [36.112.3.244])\n\tby smtp.qiye.163.com (Hmail) with ESMTP id 39aaefbde;\n\tTue, 7 Apr 2026 00:51:38 +0800 (GMT+08:00)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1775494623; cv=none;\n b=H7X7FeCUcMgLtwTnv6Bk/E+nEnyLy4Avm0TJxH4O3JgzU+Nmvi3+KJD3bSU7JPolE/E5lIrfLyG0ud6fKwbYTgTGTBzNH/vAPEkvQ3iiiytfy5+sVifbhaFFvSQHdEKmU+zxNY4NZIOLIw1wkRyN7aWKJ1luDU3LwIjcr17xI/g=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1775494623; c=relaxed/simple;\n\tbh=q24PgbY4dBpyVU6n1W0t5u+dpP3e1xtJm8tpu+KWqms=;\n\th=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:\n\t MIME-Version;\n b=ObnQq8iAxXfMNmLsnbmMO3d178m4jaq/cOiOzHHsltN34nVb+QTjKXjNUgmPs7XwJhQi+72CLgZrF09DkA1JR7lX9eGVr82/+BYopjAmObeqbiwz/wMVLA/8vY1gF+h1yLOM/YYP9Qq/9rnZf3LSu7RWdAU3r0msulNE94+Ojm8=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=ruc.edu.cn;\n spf=pass smtp.mailfrom=ruc.edu.cn;\n dkim=pass (1024-bit key) header.d=ruc.edu.cn header.i=@ruc.edu.cn\n header.b=OIBZWDGJ; arc=none smtp.client-ip=47.88.81.201","From":"Wenzhao Liao <wenzhaoliao@ruc.edu.cn>","To":"rust-for-linux@vger.kernel.org,\n\tlinux-pci@vger.kernel.org","Cc":"ojeda@kernel.org,\n\tdakr@kernel.org,\n\tbhelgaas@google.com,\n\tkwilczynski@kernel.org,\n\tarnd@arndb.de,\n\tgregkh@linuxfoundation.org,\n\tlinux-kernel@vger.kernel.org,\n\tlinux-api@vger.kernel.org","Subject":"[RFC PATCH v3 4/6] rust: pci: add shared BAR memremap support","Date":"Mon,  6 Apr 2026 12:51:18 -0400","Message-Id":"<20260406165120.166928-5-wenzhaoliao@ruc.edu.cn>","X-Mailer":"git-send-email 2.34.1","In-Reply-To":"<20260406165120.166928-1-wenzhaoliao@ruc.edu.cn>","References":"<cover.1775456181.git.wenzhaoliao@ruc.edu.cn>\n <20260406165120.166928-1-wenzhaoliao@ruc.edu.cn>","Precedence":"bulk","X-Mailing-List":"linux-pci@vger.kernel.org","List-Id":"<linux-pci.vger.kernel.org>","List-Subscribe":"<mailto:linux-pci+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-pci+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-HM-Tid":"0a9d63b4fbc603a2kunm562d3b0d647e84","X-HM-MType":"10","X-HM-Spam-Status":"e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly\n\ttZV1koWUFITzdXWS1ZQUlXWQ8JGhUIEh9ZQVkaHRpPVhpJTE5DQh5ITx5IQlYeHw5VEwETFhoSFy\n\tQUDg9ZV1kYEgtZQVlITVVKSklVSFVJT09ZV1kWGg8SFR0UWUFZT0tIVUpLSUhOQ0NVSktLVUtZBg\n\t++","DKIM-Signature":"a=rsa-sha256;\n\tb=OIBZWDGJEqJkkA2iSxbF45HhcYWe45TyqchoARpp4RJyzrduzeBQn2zcxBRGhqrfCfxacWKlk+upvfcQFJioeXB14moc1g1Pkc/b9IU1hq+JzmgP3QmODugKnf09WT0rgOozoN02KZiW/7vE+ZvPYyGHTrBBnIBM3ptkFRLAWIY=;\n c=relaxed/relaxed; s=default; d=ruc.edu.cn; v=1;\n\tbh=ZgC0mjQ5RQBGocLST6WuNwU3qiYPju/tIc008Tntz3c=;\n\th=date:mime-version:subject:message-id:from;"},"content":"Add a small Rust-owned abstraction for PCI BARs that back shared memory\ninstead of register MMIO.\n\nThe new SharedMemoryBar type owns both the BAR reservation and the\nmemremap() lifetime, exposes the physical BAR start needed by the\naddress-space ping path, and keeps the resource bookkeeping out of the\nRust driver.\n\nThe current RFC no longer exposes userspace mmap, but the driver still\nneeds an owned shared-BAR reservation and the BAR's physical base for\nthe ping path. Keeping the reservation/memremap() pairing in a Rust\nabstraction avoids pushing that lifetime bookkeeping back into driver\ncode.\n\nSigned-off-by: Wenzhao Liao <wenzhaoliao@ruc.edu.cn>\n---\n rust/kernel/pci.rs    |   8 +++\n rust/kernel/pci/id.rs |   2 +-\n rust/kernel/pci/io.rs | 112 +++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 120 insertions(+), 2 deletions(-)","diff":"diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs\nindex af74ddff6114..4c63c931ffb2 100644\n--- a/rust/kernel/pci.rs\n+++ b/rust/kernel/pci.rs\n@@ -47,6 +47,7 @@\n     ConfigSpaceSize,\n     Extended,\n     Normal, //\n+    SharedMemoryBar,\n };\n pub use self::irq::{\n     IrqType,\n@@ -458,6 +459,13 @@ pub fn set_master(&self) {\n         // SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`.\n         unsafe { bindings::pci_set_master(self.as_raw()) };\n     }\n+\n+    /// Disable this PCI device.\n+    #[inline]\n+    pub fn disable_device(&self) {\n+        // SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`.\n+        unsafe { bindings::pci_disable_device(self.as_raw()) };\n+    }\n }\n \n // SAFETY: `pci::Device` is a transparent wrapper of `struct pci_dev`.\ndiff --git a/rust/kernel/pci/id.rs b/rust/kernel/pci/id.rs\nindex 50005d176561..bd3cf17fd8de 100644\n--- a/rust/kernel/pci/id.rs\n+++ b/rust/kernel/pci/id.rs\n@@ -156,7 +156,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n impl Vendor {\n     /// Create a Vendor from a raw 16-bit vendor ID.\n     #[inline]\n-    pub(super) fn from_raw(vendor_id: u16) -> Self {\n+    pub const fn from_raw(vendor_id: u16) -> Self {\n         Self(vendor_id)\n     }\n \ndiff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs\nindex fb6edab2aea7..89bf882b9634 100644\n--- a/rust/kernel/pci/io.rs\n+++ b/rust/kernel/pci/io.rs\n@@ -7,6 +7,7 @@\n     bindings,\n     device,\n     devres::Devres,\n+    ffi::{c_ulong, c_void},\n     io::{\n         io_define_read,\n         io_define_write,\n@@ -17,11 +18,13 @@\n         MmioRaw, //\n     },\n     prelude::*,\n-    sync::aref::ARef, //\n+    sync::aref::ARef,\n+    types::ScopeGuard,\n };\n use core::{\n     marker::PhantomData,\n     ops::Deref, //\n+    ptr::NonNull,\n };\n \n /// Represents the size of a PCI configuration space.\n@@ -285,6 +288,104 @@ fn deref(&self) -> &Self::Target {\n     }\n }\n \n+/// A cacheable shared-memory mapping of a PCI BAR created via `memremap()`.\n+///\n+/// This is intended for BARs that back shared memory rather than device register MMIO. The\n+/// mapping owns both the underlying PCI region reservation and the `memremap()` lifetime, so\n+/// driver code does not need to keep raw pointers or manually pair teardown calls.\n+pub struct SharedMemoryBar {\n+    pdev: ARef<Device>,\n+    addr: NonNull<c_void>,\n+    phys_start: bindings::resource_size_t,\n+    len: usize,\n+    num: i32,\n+}\n+\n+// SAFETY: `SharedMemoryBar` owns a stable BAR reservation plus its `memremap()` mapping. Moving\n+// the owner to another thread does not change the validity of the underlying PCI resource.\n+unsafe impl Send for SharedMemoryBar {}\n+\n+// SAFETY: Shared references only expose immutable metadata queries; the mapped pointer itself is\n+// not exposed for dereferencing.\n+unsafe impl Sync for SharedMemoryBar {}\n+\n+impl SharedMemoryBar {\n+    fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> {\n+        if !Bar::index_is_valid(num) {\n+            return Err(EINVAL);\n+        }\n+\n+        let len = pdev.resource_len(num)?;\n+        if len == 0 {\n+            return Err(ENXIO);\n+        }\n+\n+        let len = usize::try_from(len)?;\n+        let phys_start = pdev.resource_start(num)?;\n+        let num = i32::try_from(num)?;\n+\n+        // SAFETY:\n+        // - `pdev` is valid by the invariants of `Device`.\n+        // - `num` is checked above.\n+        // - `name` is a valid NUL-terminated string.\n+        let ret = unsafe { bindings::pci_request_region(pdev.as_raw(), num, name.as_char_ptr()) };\n+        if ret != 0 {\n+            return Err(EBUSY);\n+        }\n+\n+        let release_region = ScopeGuard::new(|| {\n+            // SAFETY:\n+            // - `pdev` is still valid for the duration of this constructor.\n+            // - `num` has just been successfully reserved.\n+            unsafe { bindings::pci_release_region(pdev.as_raw(), num) };\n+        });\n+\n+        // SAFETY:\n+        // - `phys_start`/`len` describe the BAR range we just reserved.\n+        // - `MEMREMAP_WB` matches the external goldfish driver behaviour.\n+        let addr = unsafe { bindings::memremap(phys_start, len, bindings::MEMREMAP_WB as c_ulong) };\n+        let addr = NonNull::new(addr.cast()).ok_or(ENOMEM)?;\n+\n+        release_region.dismiss();\n+\n+        Ok(Self {\n+            pdev: pdev.into(),\n+            addr,\n+            phys_start,\n+            len,\n+            num,\n+        })\n+    }\n+\n+    /// Returns the physical start address of the BAR.\n+    #[inline]\n+    pub fn phys_start(&self) -> bindings::resource_size_t {\n+        self.phys_start\n+    }\n+\n+    /// Returns the BAR size in bytes.\n+    #[inline]\n+    pub fn len(&self) -> usize {\n+        self.len\n+    }\n+\n+    fn release(&self) {\n+        // SAFETY:\n+        // - `self.addr` is a valid `memremap()` result owned by `self`.\n+        // - `self.num` is the BAR region successfully reserved by `Self::new`.\n+        unsafe {\n+            bindings::memunmap(self.addr.as_ptr().cast());\n+            bindings::pci_release_region(self.pdev.as_raw(), self.num);\n+        }\n+    }\n+}\n+\n+impl Drop for SharedMemoryBar {\n+    fn drop(&mut self) {\n+        self.release();\n+    }\n+}\n+\n impl Device<device::Bound> {\n     /// Maps an entire PCI BAR after performing a region-request on it. I/O operation bound checks\n     /// can be performed on compile time for offsets (plus the requested type size) < SIZE.\n@@ -305,6 +406,15 @@ pub fn iomap_region<'a>(\n         self.iomap_region_sized::<0>(bar, name)\n     }\n \n+    /// Reserve and `memremap()` an entire PCI BAR as cacheable shared memory.\n+    pub fn memremap_bar<'a>(\n+        &'a self,\n+        bar: u32,\n+        name: &'a CStr,\n+    ) -> impl PinInit<Devres<SharedMemoryBar>, Error> + 'a {\n+        Devres::new(self.as_ref(), SharedMemoryBar::new(self, bar, name))\n+    }\n+\n     /// Returns the size of configuration space.\n     pub fn cfg_size(&self) -> ConfigSpaceSize {\n         // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`.\n","prefixes":["RFC","v3","4/6"]}