diff options
Diffstat (limited to 'samples/rust/rust_driver_pci.rs')
| -rw-r--r-- | samples/rust/rust_driver_pci.rs | 188 |
1 files changed, 138 insertions, 50 deletions
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 1fb6e44f3395..47d3e84fab63 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -4,30 +4,74 @@ //! //! To make this driver probe, QEMU must be run with `-device pci-testdev`. -use kernel::{bindings, c_str, devres::Devres, pci, prelude::*}; - -struct Regs; +use kernel::{ + device::{ + Bound, + Core, // + }, + devres::Devres, + io::{ + register, + register::Array, + Io, // + }, + num::Bounded, + pci, + prelude::*, + sync::aref::ARef, // +}; + +mod regs { + use super::*; + + register! { + pub(super) TEST(u8) @ 0x0 { + 7:0 index => TestIndex; + } + + pub(super) OFFSET(u32) @ 0x4 { + 31:0 offset; + } + + pub(super) DATA(u8) @ 0x8 { + 7:0 data; + } + + pub(super) COUNT(u32) @ 0xC { + 31:0 count; + } + } -impl Regs { - const TEST: usize = 0x0; - const OFFSET: usize = 0x4; - const DATA: usize = 0x8; - const COUNT: usize = 0xC; - const END: usize = 0x10; + pub(super) const END: usize = 0x10; } -type Bar0 = pci::Bar<{ Regs::END }>; +type Bar0 = pci::Bar<{ regs::END }>; -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] struct TestIndex(u8); +impl From<Bounded<u8, 8>> for TestIndex { + fn from(value: Bounded<u8, 8>) -> Self { + Self(value.into()) + } +} + +impl From<TestIndex> for Bounded<u8, 8> { + fn from(value: TestIndex) -> Self { + value.0.into() + } +} + impl TestIndex { const NO_EVENTFD: Self = Self(0); } +#[pin_data(PinnedDrop)] struct SampleDriver { - pdev: pci::Device, + pdev: ARef<pci::Device>, + #[pin] bar: Devres<Bar0>, + index: TestIndex, } kernel::pci_device_table!( @@ -35,7 +79,7 @@ kernel::pci_device_table!( MODULE_PCI_TABLE, <SampleDriver as pci::Driver>::IdInfo, [( - pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5), + pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), TestIndex::NO_EVENTFD )] ); @@ -43,68 +87,112 @@ kernel::pci_device_table!( impl SampleDriver { fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> { // Select the test. - bar.writeb(index.0, Regs::TEST); + bar.write_reg(regs::TEST::zeroed().with_index(*index)); - let offset = u32::from_le(bar.readl(Regs::OFFSET)) as usize; - let data = bar.readb(Regs::DATA); + let offset = bar.read(regs::OFFSET).into_raw() as usize; + let data = bar.read(regs::DATA).into(); // 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)?; + // Note that we need `try_write8`, since `offset` can't be checked at compile-time. + bar.try_write8(data, offset)?; - Ok(bar.readl(Regs::COUNT)) + Ok(bar.read(regs::COUNT).into()) } -} -impl pci::Driver for SampleDriver { - type IdInfo = TestIndex; + fn config_space(pdev: &pci::Device<Bound>) { + let config = pdev.config_space(); - const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; - - fn probe(pdev: &mut pci::Device, info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { - dev_dbg!( - pdev.as_ref(), - "Probe Rust PCI driver sample (PCI ID: 0x{:x}, 0x{:x}).\n", - pdev.vendor_id(), - pdev.device_id() - ); + // Some PCI configuration space registers. + register! { + VENDOR_ID(u16) @ 0x0 { + 15:0 vendor_id; + } - pdev.enable_device_mem()?; - pdev.set_master(); + REVISION_ID(u8) @ 0x8 { + 7:0 revision_id; + } - let bar = pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci"))?; + BAR(u32)[6] @ 0x10 { + 31:0 value; + } + } - let drvdata = KBox::new( - Self { - pdev: pdev.clone(), - bar, - }, - GFP_KERNEL, - )?; + dev_info!( + pdev, + "pci-testdev config space read8 rev ID: {:x}\n", + config.read(REVISION_ID).revision_id() + ); - let bar = drvdata.bar.try_access().ok_or(ENXIO)?; + dev_info!( + pdev, + "pci-testdev config space read16 vendor ID: {:x}\n", + config.read(VENDOR_ID).vendor_id() + ); dev_info!( - pdev.as_ref(), - "pci-testdev data-match count: {}\n", - Self::testdev(info, &bar)? + pdev, + "pci-testdev config space read32 BAR 0: {:x}\n", + config.read(BAR::at(0)).value() ); + } +} + +impl pci::Driver for SampleDriver { + type IdInfo = TestIndex; + + const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; + + fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> impl PinInit<Self, Error> { + pin_init::pin_init_scope(move || { + let vendor = pdev.vendor_id(); + dev_dbg!( + pdev, + "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", + vendor, + pdev.device_id() + ); + + pdev.enable_device_mem()?; + pdev.set_master(); + + Ok(try_pin_init!(Self { + bar <- pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_driver_pci"), + index: *info, + _: { + let bar = bar.access(pdev.as_ref())?; + + dev_info!( + pdev, + "pci-testdev data-match count: {}\n", + Self::testdev(info, bar)? + ); + Self::config_space(pdev); + }, + pdev: pdev.into(), + })) + }) + } - Ok(drvdata.into()) + fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) { + if let Ok(bar) = this.bar.access(pdev.as_ref()) { + // Reset pci-testdev by writing a new test index. + bar.write_reg(regs::TEST::zeroed().with_index(this.index)); + } } } -impl Drop for SampleDriver { - fn drop(&mut self) { - dev_dbg!(self.pdev.as_ref(), "Remove Rust PCI driver sample.\n"); +#[pinned_drop] +impl PinnedDrop for SampleDriver { + fn drop(self: Pin<&mut Self>) { + dev_dbg!(self.pdev, "Remove Rust PCI driver sample.\n"); } } kernel::module_pci_driver! { type: SampleDriver, name: "rust_driver_pci", - author: "Danilo Krummrich", + authors: ["Danilo Krummrich"], description: "Rust PCI driver", license: "GPL v2", } |
