]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
samples: rust: add Rust PCI sample driver
authorDanilo Krummrich <dakr@kernel.org>
Thu, 19 Dec 2024 17:04:13 +0000 (18:04 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 20 Dec 2024 16:21:04 +0000 (17:21 +0100)
This commit adds a sample Rust PCI driver for QEMU's "pci-testdev"
device. To enable this device QEMU has to be called with
`-device pci-testdev`.

The same driver shows how to use the PCI device / driver abstractions,
as well as how to request and map PCI BARs, including a short sequence of
MMIO operations.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Link: https://lore.kernel.org/r/20241219170425.12036-12-dakr@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
MAINTAINERS
samples/rust/Kconfig
samples/rust/Makefile
samples/rust/rust_driver_pci.rs [new file with mode: 0644]

index 60ae265133964cd44a0971960a6d755e4f29c8bb..2a334f2a5954e61dfb98de035db5f79bca3da774 100644 (file)
@@ -18106,6 +18106,7 @@ F:      include/linux/of_pci.h
 F:     include/linux/pci*
 F:     include/uapi/linux/pci*
 F:     rust/kernel/pci.rs
+F:     samples/rust/rust_driver_pci.rs
 
 PCIE BANDWIDTH CONTROLLER
 M:     Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
index df384e67990148d327fd65775aa89f74a14f6ac5..002af98e70be8b0bd61d353cf5800dc2c04d3bb7 100644 (file)
@@ -40,6 +40,17 @@ config SAMPLE_RUST_PRINT
 
          If unsure, say N.
 
+config SAMPLE_RUST_DRIVER_PCI
+       tristate "PCI Driver"
+       depends on PCI
+       help
+         This option builds the Rust PCI driver sample.
+
+         To compile this as a module, choose M here:
+         the module will be called driver_pci.
+
+         If unsure, say N.
+
 config SAMPLE_RUST_HOSTPROGS
        bool "Host programs"
        help
index ad4b97a985809934acfc4023199cc21ef743023e..b4581473ca1b9211913868d6652b10d3dc0dea1d 100644 (file)
@@ -4,6 +4,7 @@ ccflags-y += -I$(src)                           # needed for trace events
 obj-$(CONFIG_SAMPLE_RUST_MINIMAL)              += rust_minimal.o
 obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE)          += rust_misc_device.o
 obj-$(CONFIG_SAMPLE_RUST_PRINT)                        += rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI)           += rust_driver_pci.o
 
 rust_print-y := rust_print_main.o rust_print_events.o
 
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
new file mode 100644 (file)
index 0000000..1fb6e44
--- /dev/null
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust PCI driver sample (based on QEMU's `pci-testdev`).
+//!
+//! To make this driver probe, QEMU must be run with `-device pci-testdev`.
+
+use kernel::{bindings, c_str, devres::Devres, pci, prelude::*};
+
+struct Regs;
+
+impl Regs {
+    const TEST: usize = 0x0;
+    const OFFSET: usize = 0x4;
+    const DATA: usize = 0x8;
+    const COUNT: usize = 0xC;
+    const END: usize = 0x10;
+}
+
+type Bar0 = pci::Bar<{ Regs::END }>;
+
+#[derive(Debug)]
+struct TestIndex(u8);
+
+impl TestIndex {
+    const NO_EVENTFD: Self = Self(0);
+}
+
+struct SampleDriver {
+    pdev: pci::Device,
+    bar: Devres<Bar0>,
+}
+
+kernel::pci_device_table!(
+    PCI_TABLE,
+    MODULE_PCI_TABLE,
+    <SampleDriver as pci::Driver>::IdInfo,
+    [(
+        pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
+        TestIndex::NO_EVENTFD
+    )]
+);
+
+impl SampleDriver {
+    fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> {
+        // Select the test.
+        bar.writeb(index.0, Regs::TEST);
+
+        let offset = u32::from_le(bar.readl(Regs::OFFSET)) as usize;
+        let data = bar.readb(Regs::DATA);
+
+        // Write `data` to `offset` to increase `count` by one.
+        //
+        // Note that we need `try_writeb`, since `offset` can't be checked at compile-time.
+        bar.try_writeb(data, offset)?;
+
+        Ok(bar.readl(Regs::COUNT))
+    }
+}
+
+impl pci::Driver for SampleDriver {
+    type IdInfo = TestIndex;
+
+    const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
+
+    fn probe(pdev: &mut pci::Device, info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
+        dev_dbg!(
+            pdev.as_ref(),
+            "Probe Rust PCI driver sample (PCI ID: 0x{:x}, 0x{:x}).\n",
+            pdev.vendor_id(),
+            pdev.device_id()
+        );
+
+        pdev.enable_device_mem()?;
+        pdev.set_master();
+
+        let bar = pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci"))?;
+
+        let drvdata = KBox::new(
+            Self {
+                pdev: pdev.clone(),
+                bar,
+            },
+            GFP_KERNEL,
+        )?;
+
+        let bar = drvdata.bar.try_access().ok_or(ENXIO)?;
+
+        dev_info!(
+            pdev.as_ref(),
+            "pci-testdev data-match count: {}\n",
+            Self::testdev(info, &bar)?
+        );
+
+        Ok(drvdata.into())
+    }
+}
+
+impl Drop for SampleDriver {
+    fn drop(&mut self) {
+        dev_dbg!(self.pdev.as_ref(), "Remove Rust PCI driver sample.\n");
+    }
+}
+
+kernel::module_pci_driver! {
+    type: SampleDriver,
+    name: "rust_driver_pci",
+    author: "Danilo Krummrich",
+    description: "Rust PCI driver",
+    license: "GPL v2",
+}