Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

samples: rust: add Rust PCI sample driver

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>

authored by

Danilo Krummrich and committed by
Greg Kroah-Hartman
685376d1 bf9651f8

+123
+1
MAINTAINERS
··· 18106 18106 F: include/linux/pci* 18107 18107 F: include/uapi/linux/pci* 18108 18108 F: rust/kernel/pci.rs 18109 + F: samples/rust/rust_driver_pci.rs 18109 18110 18110 18111 PCIE BANDWIDTH CONTROLLER 18111 18112 M: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+11
samples/rust/Kconfig
··· 40 40 41 41 If unsure, say N. 42 42 43 + config SAMPLE_RUST_DRIVER_PCI 44 + tristate "PCI Driver" 45 + depends on PCI 46 + help 47 + This option builds the Rust PCI driver sample. 48 + 49 + To compile this as a module, choose M here: 50 + the module will be called driver_pci. 51 + 52 + If unsure, say N. 53 + 43 54 config SAMPLE_RUST_HOSTPROGS 44 55 bool "Host programs" 45 56 help
+1
samples/rust/Makefile
··· 4 4 obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o 5 5 obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) += rust_misc_device.o 6 6 obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o 7 + obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o 7 8 8 9 rust_print-y := rust_print_main.o rust_print_events.o 9 10
+110
samples/rust/rust_driver_pci.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Rust PCI driver sample (based on QEMU's `pci-testdev`). 4 + //! 5 + //! To make this driver probe, QEMU must be run with `-device pci-testdev`. 6 + 7 + use kernel::{bindings, c_str, devres::Devres, pci, prelude::*}; 8 + 9 + struct Regs; 10 + 11 + impl Regs { 12 + const TEST: usize = 0x0; 13 + const OFFSET: usize = 0x4; 14 + const DATA: usize = 0x8; 15 + const COUNT: usize = 0xC; 16 + const END: usize = 0x10; 17 + } 18 + 19 + type Bar0 = pci::Bar<{ Regs::END }>; 20 + 21 + #[derive(Debug)] 22 + struct TestIndex(u8); 23 + 24 + impl TestIndex { 25 + const NO_EVENTFD: Self = Self(0); 26 + } 27 + 28 + struct SampleDriver { 29 + pdev: pci::Device, 30 + bar: Devres<Bar0>, 31 + } 32 + 33 + kernel::pci_device_table!( 34 + PCI_TABLE, 35 + MODULE_PCI_TABLE, 36 + <SampleDriver as pci::Driver>::IdInfo, 37 + [( 38 + pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5), 39 + TestIndex::NO_EVENTFD 40 + )] 41 + ); 42 + 43 + impl SampleDriver { 44 + fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> { 45 + // Select the test. 46 + bar.writeb(index.0, Regs::TEST); 47 + 48 + let offset = u32::from_le(bar.readl(Regs::OFFSET)) as usize; 49 + let data = bar.readb(Regs::DATA); 50 + 51 + // Write `data` to `offset` to increase `count` by one. 52 + // 53 + // Note that we need `try_writeb`, since `offset` can't be checked at compile-time. 54 + bar.try_writeb(data, offset)?; 55 + 56 + Ok(bar.readl(Regs::COUNT)) 57 + } 58 + } 59 + 60 + impl pci::Driver for SampleDriver { 61 + type IdInfo = TestIndex; 62 + 63 + const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; 64 + 65 + fn probe(pdev: &mut pci::Device, info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { 66 + dev_dbg!( 67 + pdev.as_ref(), 68 + "Probe Rust PCI driver sample (PCI ID: 0x{:x}, 0x{:x}).\n", 69 + pdev.vendor_id(), 70 + pdev.device_id() 71 + ); 72 + 73 + pdev.enable_device_mem()?; 74 + pdev.set_master(); 75 + 76 + let bar = pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci"))?; 77 + 78 + let drvdata = KBox::new( 79 + Self { 80 + pdev: pdev.clone(), 81 + bar, 82 + }, 83 + GFP_KERNEL, 84 + )?; 85 + 86 + let bar = drvdata.bar.try_access().ok_or(ENXIO)?; 87 + 88 + dev_info!( 89 + pdev.as_ref(), 90 + "pci-testdev data-match count: {}\n", 91 + Self::testdev(info, &bar)? 92 + ); 93 + 94 + Ok(drvdata.into()) 95 + } 96 + } 97 + 98 + impl Drop for SampleDriver { 99 + fn drop(&mut self) { 100 + dev_dbg!(self.pdev.as_ref(), "Remove Rust PCI driver sample.\n"); 101 + } 102 + } 103 + 104 + kernel::module_pci_driver! { 105 + type: SampleDriver, 106 + name: "rust_driver_pci", 107 + author: "Danilo Krummrich", 108 + description: "Rust PCI driver", 109 + license: "GPL v2", 110 + }