forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 431
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Danilo Krummrich
committed
Oct 22, 2024
1 parent
d363355
commit c13795f
Showing
4 changed files
with
122 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// 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::new(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(u32::from_le(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, | ||
_id: &pci::DeviceId, | ||
info: &Self::IdInfo, | ||
) -> Result<Pin<KBox<Self>>> { | ||
dev_dbg!(pdev.as_ref(), "Probe Rust PCI driver sample.\n"); | ||
|
||
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", | ||
} |