xref: /linux/samples/rust/rust_driver_pci.rs (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1685376d1SDanilo Krummrich // SPDX-License-Identifier: GPL-2.0
2685376d1SDanilo Krummrich 
3685376d1SDanilo Krummrich //! Rust PCI driver sample (based on QEMU's `pci-testdev`).
4685376d1SDanilo Krummrich //!
5685376d1SDanilo Krummrich //! To make this driver probe, QEMU must be run with `-device pci-testdev`.
6685376d1SDanilo Krummrich 
7*7b948a2aSDanilo Krummrich use kernel::{bindings, c_str, device::Core, devres::Devres, pci, prelude::*, types::ARef};
8685376d1SDanilo Krummrich 
9685376d1SDanilo Krummrich struct Regs;
10685376d1SDanilo Krummrich 
11685376d1SDanilo Krummrich impl Regs {
12685376d1SDanilo Krummrich     const TEST: usize = 0x0;
13685376d1SDanilo Krummrich     const OFFSET: usize = 0x4;
14685376d1SDanilo Krummrich     const DATA: usize = 0x8;
15685376d1SDanilo Krummrich     const COUNT: usize = 0xC;
16685376d1SDanilo Krummrich     const END: usize = 0x10;
17685376d1SDanilo Krummrich }
18685376d1SDanilo Krummrich 
19685376d1SDanilo Krummrich type Bar0 = pci::Bar<{ Regs::END }>;
20685376d1SDanilo Krummrich 
21685376d1SDanilo Krummrich #[derive(Debug)]
22685376d1SDanilo Krummrich struct TestIndex(u8);
23685376d1SDanilo Krummrich 
24685376d1SDanilo Krummrich impl TestIndex {
25685376d1SDanilo Krummrich     const NO_EVENTFD: Self = Self(0);
26685376d1SDanilo Krummrich }
27685376d1SDanilo Krummrich 
28685376d1SDanilo Krummrich struct SampleDriver {
29*7b948a2aSDanilo Krummrich     pdev: ARef<pci::Device>,
30685376d1SDanilo Krummrich     bar: Devres<Bar0>,
31685376d1SDanilo Krummrich }
32685376d1SDanilo Krummrich 
33685376d1SDanilo Krummrich kernel::pci_device_table!(
34685376d1SDanilo Krummrich     PCI_TABLE,
35685376d1SDanilo Krummrich     MODULE_PCI_TABLE,
36685376d1SDanilo Krummrich     <SampleDriver as pci::Driver>::IdInfo,
37685376d1SDanilo Krummrich     [(
38685376d1SDanilo Krummrich         pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
39685376d1SDanilo Krummrich         TestIndex::NO_EVENTFD
40685376d1SDanilo Krummrich     )]
41685376d1SDanilo Krummrich );
42685376d1SDanilo Krummrich 
43685376d1SDanilo Krummrich impl SampleDriver {
44685376d1SDanilo Krummrich     fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> {
45685376d1SDanilo Krummrich         // Select the test.
46354fd6e8SFiona Behrens         bar.write8(index.0, Regs::TEST);
47685376d1SDanilo Krummrich 
48354fd6e8SFiona Behrens         let offset = u32::from_le(bar.read32(Regs::OFFSET)) as usize;
49354fd6e8SFiona Behrens         let data = bar.read8(Regs::DATA);
50685376d1SDanilo Krummrich 
51685376d1SDanilo Krummrich         // Write `data` to `offset` to increase `count` by one.
52685376d1SDanilo Krummrich         //
53354fd6e8SFiona Behrens         // Note that we need `try_write8`, since `offset` can't be checked at compile-time.
54354fd6e8SFiona Behrens         bar.try_write8(data, offset)?;
55685376d1SDanilo Krummrich 
56354fd6e8SFiona Behrens         Ok(bar.read32(Regs::COUNT))
57685376d1SDanilo Krummrich     }
58685376d1SDanilo Krummrich }
59685376d1SDanilo Krummrich 
60685376d1SDanilo Krummrich impl pci::Driver for SampleDriver {
61685376d1SDanilo Krummrich     type IdInfo = TestIndex;
62685376d1SDanilo Krummrich 
63685376d1SDanilo Krummrich     const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
64685376d1SDanilo Krummrich 
65*7b948a2aSDanilo Krummrich     fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
66685376d1SDanilo Krummrich         dev_dbg!(
67685376d1SDanilo Krummrich             pdev.as_ref(),
68685376d1SDanilo Krummrich             "Probe Rust PCI driver sample (PCI ID: 0x{:x}, 0x{:x}).\n",
69685376d1SDanilo Krummrich             pdev.vendor_id(),
70685376d1SDanilo Krummrich             pdev.device_id()
71685376d1SDanilo Krummrich         );
72685376d1SDanilo Krummrich 
73685376d1SDanilo Krummrich         pdev.enable_device_mem()?;
74685376d1SDanilo Krummrich         pdev.set_master();
75685376d1SDanilo Krummrich 
76685376d1SDanilo Krummrich         let bar = pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci"))?;
77685376d1SDanilo Krummrich 
78685376d1SDanilo Krummrich         let drvdata = KBox::new(
79685376d1SDanilo Krummrich             Self {
80*7b948a2aSDanilo Krummrich                 pdev: pdev.into(),
81685376d1SDanilo Krummrich                 bar,
82685376d1SDanilo Krummrich             },
83685376d1SDanilo Krummrich             GFP_KERNEL,
84685376d1SDanilo Krummrich         )?;
85685376d1SDanilo Krummrich 
86685376d1SDanilo Krummrich         let bar = drvdata.bar.try_access().ok_or(ENXIO)?;
87685376d1SDanilo Krummrich 
88685376d1SDanilo Krummrich         dev_info!(
89685376d1SDanilo Krummrich             pdev.as_ref(),
90685376d1SDanilo Krummrich             "pci-testdev data-match count: {}\n",
91685376d1SDanilo Krummrich             Self::testdev(info, &bar)?
92685376d1SDanilo Krummrich         );
93685376d1SDanilo Krummrich 
94685376d1SDanilo Krummrich         Ok(drvdata.into())
95685376d1SDanilo Krummrich     }
96685376d1SDanilo Krummrich }
97685376d1SDanilo Krummrich 
98685376d1SDanilo Krummrich impl Drop for SampleDriver {
99685376d1SDanilo Krummrich     fn drop(&mut self) {
100685376d1SDanilo Krummrich         dev_dbg!(self.pdev.as_ref(), "Remove Rust PCI driver sample.\n");
101685376d1SDanilo Krummrich     }
102685376d1SDanilo Krummrich }
103685376d1SDanilo Krummrich 
104685376d1SDanilo Krummrich kernel::module_pci_driver! {
105685376d1SDanilo Krummrich     type: SampleDriver,
106685376d1SDanilo Krummrich     name: "rust_driver_pci",
10738559da6SGuilherme Giacomo Simoes     authors: ["Danilo Krummrich"],
108685376d1SDanilo Krummrich     description: "Rust PCI driver",
109685376d1SDanilo Krummrich     license: "GPL v2",
110685376d1SDanilo Krummrich }
111