The Rust sample drivers currently exercise PCI facilities in isolation: rust_driver_pci covers MMIO and rust_dma covers DMA, but there is no single in-tree example that combines memory-mapped I/O, interrupts and DMA in one driver.
This series adds one. It targets QEMU's `edu` device -- a small, well-documented educational PCI device that supports exactly these three facilities and ships with any recent QEMU (`-device edu`), so the sample runs without special hardware. The sample maps BAR0, reads the PCI configuration space, and runs a set of MMIO self-tests (identification, liveness, factorial), allocates an MSI vector and registers an IRQ handler, and performs a DMA round-trip. The IRQ and DMA tests wait on a `Completion` signalled by the IRQ handler; the factorial test polls for completion. As requested by Danilo in the v2 review, the sample replaces rust_driver_pci, which it covers a superset of; the removal is the first patch. Prerequisites that had to be implemented: - pci: rework the device enabling API: replace enable_device_mem() with enable_device(), which returns a DeviceEnableGuard that disables the device again on drop, so the enable count stays balanced across unbind/rebind. This follows the design Danilo proposed in the review of the standalone patch [1], which this series absorbs. - pci: keep `set_master()` on `Device<Core>` and require a borrowed `DeviceEnableGuard` for the same device, preserving callback synchronization while ensuring the device is enabled. - pci: add PCI_VENDOR_ID_QEMU (0x1234) to pci_ids.h and expose it as Vendor::QEMU, so the sample can match the device. - completion: add complete(), so a single Completion can be reused to wait for consecutive events (e.g. back-to-back DMA transfers). The series is based on rust/rust-next. Note: DeviceEnableGuard drops from a bound scope, so pci_disable_device() can race the pci_dev bitfield word as discussed in [1]; that race predates this series and is triggerable from sysfs today. The bitops conversion is under way separately on linux-pci [3]. Tested with QEMU `-device edu`. Not taken from the v3 review (Sashiko): - The IRQ and DMA completion waits remain unbounded; missing interrupts can block probe. - enable_device() uses pci_enable_device(), not pci_enable_device_mem(): it is the single enable API Danilo proposed, and enabling I/O decoding is harmless for memory-only devices. [1] https://lore.kernel.org/rust-for-linux/[email protected] [2] https://lore.kernel.org/r/[email protected] [3] https://lore.kernel.org/linux-pci/[email protected]/ Signed-off-by: Maurice Hieronymus <[email protected]> --- Changes in v4: - Drop "rust: pci: make Vendor::from_raw() public" (and its R-b tags); instead add PCI_VENDOR_ID_QEMU to pci_ids.h and expose it as Vendor::QEMU (new patches 4-5) (Alice, John). - New patch: pci: require a borrowed enable guard for the same device in `set_master()`, retaining `Device<Core>` callback synchronization; convert nova-core. This enforces enabling before bus-mastering (Danilo) while addressing the concurrency concern (Sashiko). - pci: mark DeviceEnableGuard #[must_use] and enable_device() #[inline] (Sashiko, Fiona). - completion: reference complete() from wait_for_completion()'s docs (Gary). - samples/edu: turn init() and the test helpers into methods on EduDriverData; rename init() to selftest() (Danilo). - samples/edu: initialize EduDriverData in a single try_pin_init!(), holding the IRQ vectors and registering the handler with irq::Registration::new() instead of pci::Device::request_irq(); run selftest() via pin_chain() (Danilo). - samples/edu: make the magic and DMA base constants local to their users; check the magic via an IDENTIFICATION constant (Danilo). - samples/edu: describe the DMA and test IRQ bits as fields of IRQ_STATUS/IRQ_RAISE/IRQ_ACK instead of a DMA_IRQ constant (Danilo). - samples/edu: model the DMA registers as a struct accessed through io_project!()/io_write!(). - samples/edu: compare the liveness pattern via a Not impl on LIVENESS_CHECK (Danilo). - samples/edu: replace `as` casts with safe casts (Danilo). - samples/edu: return IrqReturn::None for interrupts that are not ours (Sashiko). - samples/edu: depend on 64BIT for the 64-bit MMIO accesses (Sashiko). - samples/edu: expand the commit message and Kconfig help to describe the sample's coverage, QEMU usage and the 64BIT requirement; mention the MAINTAINERS entry in the commit message (Sashiko). - samples/edu: ack stale interrupts before registering the handler (Sashiko). - samples/edu: spell out why the IRQ Registration is not leaked (Ewan). - Drop the dependency on Danilo's irq Registration rework [2], now in mainline. - Rebase on rust-next; adapt to register!() `base:`, Option<&IdInfo> in probe() and the Coherent read_val()/write_val() API. - Link to v3: https://lore.kernel.org/r/[email protected] Changes in v3: - Absorb the device enabling rework [1] into this series, redesigned around DeviceEnableGuard as proposed by Danilo; convert nova-core. - Remove rust_driver_pci, replaced by this sample (Danilo). - Add access to PCI configuration space (Danilo). - Rebase on rust/rust-next on top of Danilo's irq Registration rework [2]; register the handler via pci::Device::request_irq(). - Use vertical import style. - Link to v2: https://lore.kernel.org/r/[email protected] Changes in v2: - pci: Vendor::from_raw(): collected Reviewed-by from Gary Guo; wrapped code identifiers in the commit message in backticks (Gary). - pci: enable_device(): collected Reviewed-by from Fiona Behrens; made enable_device_mem() #[inline] and added a cross-reference to enable_device() in its docs (Fiona). - completion: complete(): tightened the doc comment per Gary's review (emphasise "single", drop the internal-counter detail, drop the complete_all comparison). - samples/edu: take &EduDriverData instead of &Arc<EduDriverData> in init()/test_irq()/test_dma() (Ewan Chorynski). - samples/edu: simplify wait_until_compute_has_finished() to forward read_poll_timeout()'s error via inspect_err() instead of returning a hard-coded ETIMEDOUT (Ewan Chorynski / Miguel Ojeda). - samples/edu: Rebased on rust/rust-next and adapt to the updated pci::Bar / device::Core lifetimes and pci::Driver::Data<'bound>, and obtain the BAR via into_devres(). - Link to v1: https://lore.kernel.org/r/[email protected] --- Maurice Hieronymus (7): samples: rust: remove the rust_driver_pci sample rust: pci: rework device enabling API rust: pci: require an enable guard for `set_master()` PCI: Add QEMU vendor ID rust: pci: add Vendor::QEMU rust: completion: add complete() samples: rust: add EDU PCI driver sample MAINTAINERS | 2 +- drivers/gpu/nova-core/driver.rs | 9 +- include/linux/pci_ids.h | 2 + rust/kernel/pci.rs | 45 +++- rust/kernel/pci/id.rs | 1 + rust/kernel/sync/completion.rs | 13 +- samples/rust/Kconfig | 14 +- samples/rust/Makefile | 2 +- samples/rust/rust_driver_edu.rs | 475 ++++++++++++++++++++++++++++++++++++++++ samples/rust/rust_driver_pci.rs | 198 ----------------- 10 files changed, 547 insertions(+), 214 deletions(-) --- base-commit: d89e1d186ec9271bf78e62771779e9fc03bf0fc3 change-id: 20260614-b4-rust-pci-edu-driver-3e50db2dda0f Best regards, -- Maurice Hieronymus <[email protected]>
