xref: /linux/samples/rust/rust_dma.rs (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
19901addaSAbdiel Janulgue // SPDX-License-Identifier: GPL-2.0
29901addaSAbdiel Janulgue 
39901addaSAbdiel Janulgue //! Rust DMA api test (based on QEMU's `pci-testdev`).
49901addaSAbdiel Janulgue //!
59901addaSAbdiel Janulgue //! To make this driver probe, QEMU must be run with `-device pci-testdev`.
69901addaSAbdiel Janulgue 
7*2cd5769fSLinus Torvalds use kernel::{bindings, device::Core, dma::CoherentAllocation, pci, prelude::*, types::ARef};
89901addaSAbdiel Janulgue 
99901addaSAbdiel Janulgue struct DmaSampleDriver {
10*2cd5769fSLinus Torvalds     pdev: ARef<pci::Device>,
119901addaSAbdiel Janulgue     ca: CoherentAllocation<MyStruct>,
129901addaSAbdiel Janulgue }
139901addaSAbdiel Janulgue 
149901addaSAbdiel Janulgue const TEST_VALUES: [(u32, u32); 5] = [
159901addaSAbdiel Janulgue     (0xa, 0xb),
169901addaSAbdiel Janulgue     (0xc, 0xd),
179901addaSAbdiel Janulgue     (0xe, 0xf),
189901addaSAbdiel Janulgue     (0xab, 0xba),
199901addaSAbdiel Janulgue     (0xcd, 0xef),
209901addaSAbdiel Janulgue ];
219901addaSAbdiel Janulgue 
229901addaSAbdiel Janulgue struct MyStruct {
239901addaSAbdiel Janulgue     h: u32,
249901addaSAbdiel Janulgue     b: u32,
259901addaSAbdiel Janulgue }
269901addaSAbdiel Janulgue 
279901addaSAbdiel Janulgue impl MyStruct {
289901addaSAbdiel Janulgue     fn new(h: u32, b: u32) -> Self {
299901addaSAbdiel Janulgue         Self { h, b }
309901addaSAbdiel Janulgue     }
319901addaSAbdiel Janulgue }
329901addaSAbdiel Janulgue // SAFETY: All bit patterns are acceptable values for `MyStruct`.
339901addaSAbdiel Janulgue unsafe impl kernel::transmute::AsBytes for MyStruct {}
349901addaSAbdiel Janulgue // SAFETY: Instances of `MyStruct` have no uninitialized portions.
359901addaSAbdiel Janulgue unsafe impl kernel::transmute::FromBytes for MyStruct {}
369901addaSAbdiel Janulgue 
379901addaSAbdiel Janulgue kernel::pci_device_table!(
389901addaSAbdiel Janulgue     PCI_TABLE,
399901addaSAbdiel Janulgue     MODULE_PCI_TABLE,
409901addaSAbdiel Janulgue     <DmaSampleDriver as pci::Driver>::IdInfo,
419901addaSAbdiel Janulgue     [(
429901addaSAbdiel Janulgue         pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
439901addaSAbdiel Janulgue         ()
449901addaSAbdiel Janulgue     )]
459901addaSAbdiel Janulgue );
469901addaSAbdiel Janulgue 
479901addaSAbdiel Janulgue impl pci::Driver for DmaSampleDriver {
489901addaSAbdiel Janulgue     type IdInfo = ();
499901addaSAbdiel Janulgue     const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
509901addaSAbdiel Janulgue 
51*2cd5769fSLinus Torvalds     fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
529901addaSAbdiel Janulgue         dev_info!(pdev.as_ref(), "Probe DMA test driver.\n");
539901addaSAbdiel Janulgue 
549901addaSAbdiel Janulgue         let ca: CoherentAllocation<MyStruct> =
559901addaSAbdiel Janulgue             CoherentAllocation::alloc_coherent(pdev.as_ref(), TEST_VALUES.len(), GFP_KERNEL)?;
569901addaSAbdiel Janulgue 
579901addaSAbdiel Janulgue         || -> Result {
589901addaSAbdiel Janulgue             for (i, value) in TEST_VALUES.into_iter().enumerate() {
599901addaSAbdiel Janulgue                 kernel::dma_write!(ca[i] = MyStruct::new(value.0, value.1));
609901addaSAbdiel Janulgue             }
619901addaSAbdiel Janulgue 
629901addaSAbdiel Janulgue             Ok(())
639901addaSAbdiel Janulgue         }()?;
649901addaSAbdiel Janulgue 
659901addaSAbdiel Janulgue         let drvdata = KBox::new(
669901addaSAbdiel Janulgue             Self {
67*2cd5769fSLinus Torvalds                 pdev: pdev.into(),
689901addaSAbdiel Janulgue                 ca,
699901addaSAbdiel Janulgue             },
709901addaSAbdiel Janulgue             GFP_KERNEL,
719901addaSAbdiel Janulgue         )?;
729901addaSAbdiel Janulgue 
739901addaSAbdiel Janulgue         Ok(drvdata.into())
749901addaSAbdiel Janulgue     }
759901addaSAbdiel Janulgue }
769901addaSAbdiel Janulgue 
779901addaSAbdiel Janulgue impl Drop for DmaSampleDriver {
789901addaSAbdiel Janulgue     fn drop(&mut self) {
799901addaSAbdiel Janulgue         dev_info!(self.pdev.as_ref(), "Unload DMA test driver.\n");
809901addaSAbdiel Janulgue 
819901addaSAbdiel Janulgue         let _ = || -> Result {
829901addaSAbdiel Janulgue             for (i, value) in TEST_VALUES.into_iter().enumerate() {
839901addaSAbdiel Janulgue                 assert_eq!(kernel::dma_read!(self.ca[i].h), value.0);
849901addaSAbdiel Janulgue                 assert_eq!(kernel::dma_read!(self.ca[i].b), value.1);
859901addaSAbdiel Janulgue             }
869901addaSAbdiel Janulgue             Ok(())
879901addaSAbdiel Janulgue         }();
889901addaSAbdiel Janulgue     }
899901addaSAbdiel Janulgue }
909901addaSAbdiel Janulgue 
919901addaSAbdiel Janulgue kernel::module_pci_driver! {
929901addaSAbdiel Janulgue     type: DmaSampleDriver,
939901addaSAbdiel Janulgue     name: "rust_dma",
949901addaSAbdiel Janulgue     authors: ["Abdiel Janulgue"],
959901addaSAbdiel Janulgue     description: "Rust DMA test",
969901addaSAbdiel Janulgue     license: "GPL v2",
979901addaSAbdiel Janulgue }
98