Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/samples/rust/rust_driver_pci.rs
26285 views
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, device::Core, devres::Devres, pci, prelude::*, types::ARef};
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(Copy, Clone, Debug)]
22
struct TestIndex(u8);
23
24
impl TestIndex {
25
const NO_EVENTFD: Self = Self(0);
26
}
27
28
#[pin_data(PinnedDrop)]
29
struct SampleDriver {
30
pdev: ARef<pci::Device>,
31
#[pin]
32
bar: Devres<Bar0>,
33
index: TestIndex,
34
}
35
36
kernel::pci_device_table!(
37
PCI_TABLE,
38
MODULE_PCI_TABLE,
39
<SampleDriver as pci::Driver>::IdInfo,
40
[(
41
pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
42
TestIndex::NO_EVENTFD
43
)]
44
);
45
46
impl SampleDriver {
47
fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> {
48
// Select the test.
49
bar.write8(index.0, Regs::TEST);
50
51
let offset = u32::from_le(bar.read32(Regs::OFFSET)) as usize;
52
let data = bar.read8(Regs::DATA);
53
54
// Write `data` to `offset` to increase `count` by one.
55
//
56
// Note that we need `try_write8`, since `offset` can't be checked at compile-time.
57
bar.try_write8(data, offset)?;
58
59
Ok(bar.read32(Regs::COUNT))
60
}
61
}
62
63
impl pci::Driver for SampleDriver {
64
type IdInfo = TestIndex;
65
66
const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
67
68
fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
69
dev_dbg!(
70
pdev.as_ref(),
71
"Probe Rust PCI driver sample (PCI ID: 0x{:x}, 0x{:x}).\n",
72
pdev.vendor_id(),
73
pdev.device_id()
74
);
75
76
pdev.enable_device_mem()?;
77
pdev.set_master();
78
79
let drvdata = KBox::pin_init(
80
try_pin_init!(Self {
81
pdev: pdev.into(),
82
bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci")),
83
index: *info,
84
}),
85
GFP_KERNEL,
86
)?;
87
88
let bar = drvdata.bar.access(pdev.as_ref())?;
89
dev_info!(
90
pdev.as_ref(),
91
"pci-testdev data-match count: {}\n",
92
Self::testdev(info, bar)?
93
);
94
95
Ok(drvdata)
96
}
97
98
fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) {
99
if let Ok(bar) = this.bar.access(pdev.as_ref()) {
100
// Reset pci-testdev by writing a new test index.
101
bar.write8(this.index.0, Regs::TEST);
102
}
103
}
104
}
105
106
#[pinned_drop]
107
impl PinnedDrop for SampleDriver {
108
fn drop(self: Pin<&mut Self>) {
109
dev_dbg!(self.pdev.as_ref(), "Remove Rust PCI driver sample.\n");
110
}
111
}
112
113
kernel::module_pci_driver! {
114
type: SampleDriver,
115
name: "rust_driver_pci",
116
authors: ["Danilo Krummrich"],
117
description: "Rust PCI driver",
118
license: "GPL v2",
119
}
120
121