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