Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
7use kernel::{bindings, c_str, device::Core, devres::Devres, pci, prelude::*, types::ARef};
8
9struct Regs;
10
11impl 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
19type Bar0 = pci::Bar<{ Regs::END }>;
20
21#[derive(Debug)]
22struct TestIndex(u8);
23
24impl TestIndex {
25 const NO_EVENTFD: Self = Self(0);
26}
27
28struct SampleDriver {
29 pdev: ARef<pci::Device>,
30 bar: Devres<Bar0>,
31}
32
33kernel::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
43impl SampleDriver {
44 fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> {
45 // Select the test.
46 bar.write8(index.0, Regs::TEST);
47
48 let offset = u32::from_le(bar.read32(Regs::OFFSET)) as usize;
49 let data = bar.read8(Regs::DATA);
50
51 // Write `data` to `offset` to increase `count` by one.
52 //
53 // Note that we need `try_write8`, since `offset` can't be checked at compile-time.
54 bar.try_write8(data, offset)?;
55
56 Ok(bar.read32(Regs::COUNT))
57 }
58}
59
60impl pci::Driver for SampleDriver {
61 type IdInfo = TestIndex;
62
63 const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
64
65 fn probe(pdev: &pci::Device<Core>, 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.into(),
81 bar,
82 },
83 GFP_KERNEL,
84 )?;
85
86 let bar = drvdata.bar.access(pdev.as_ref())?;
87 dev_info!(
88 pdev.as_ref(),
89 "pci-testdev data-match count: {}\n",
90 Self::testdev(info, bar)?
91 );
92
93 Ok(drvdata.into())
94 }
95}
96
97impl Drop for SampleDriver {
98 fn drop(&mut self) {
99 dev_dbg!(self.pdev.as_ref(), "Remove Rust PCI driver sample.\n");
100 }
101}
102
103kernel::module_pci_driver! {
104 type: SampleDriver,
105 name: "rust_driver_pci",
106 authors: ["Danilo Krummrich"],
107 description: "Rust PCI driver",
108 license: "GPL v2",
109}