rust_driver_pci.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // SPDX-License-Identifier: GPL-2.0
  2. //! Rust PCI driver sample (based on QEMU's `pci-testdev`).
  3. //!
  4. //! To make this driver probe, QEMU must be run with `-device pci-testdev`.
  5. use kernel::{
  6. device::Bound,
  7. device::Core,
  8. devres::Devres,
  9. io::Io,
  10. pci,
  11. prelude::*,
  12. sync::aref::ARef, //
  13. };
  14. struct Regs;
  15. impl Regs {
  16. const TEST: usize = 0x0;
  17. const OFFSET: usize = 0x4;
  18. const DATA: usize = 0x8;
  19. const COUNT: usize = 0xC;
  20. const END: usize = 0x10;
  21. }
  22. type Bar0 = pci::Bar<{ Regs::END }>;
  23. #[derive(Copy, Clone, Debug)]
  24. struct TestIndex(u8);
  25. impl TestIndex {
  26. const NO_EVENTFD: Self = Self(0);
  27. }
  28. #[pin_data(PinnedDrop)]
  29. struct SampleDriver {
  30. pdev: ARef<pci::Device>,
  31. #[pin]
  32. bar: Devres<Bar0>,
  33. index: TestIndex,
  34. }
  35. kernel::pci_device_table!(
  36. PCI_TABLE,
  37. MODULE_PCI_TABLE,
  38. <SampleDriver as pci::Driver>::IdInfo,
  39. [(
  40. pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5),
  41. TestIndex::NO_EVENTFD
  42. )]
  43. );
  44. impl SampleDriver {
  45. fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> {
  46. // Select the test.
  47. bar.write8(index.0, Regs::TEST);
  48. let offset = bar.read32(Regs::OFFSET) as usize;
  49. let data = bar.read8(Regs::DATA);
  50. // Write `data` to `offset` to increase `count` by one.
  51. //
  52. // Note that we need `try_write8`, since `offset` can't be checked at compile-time.
  53. bar.try_write8(data, offset)?;
  54. Ok(bar.read32(Regs::COUNT))
  55. }
  56. fn config_space(pdev: &pci::Device<Bound>) {
  57. let config = pdev.config_space();
  58. // TODO: use the register!() macro for defining PCI configuration space registers once it
  59. // has been move out of nova-core.
  60. dev_info!(
  61. pdev,
  62. "pci-testdev config space read8 rev ID: {:x}\n",
  63. config.read8(0x8)
  64. );
  65. dev_info!(
  66. pdev,
  67. "pci-testdev config space read16 vendor ID: {:x}\n",
  68. config.read16(0)
  69. );
  70. dev_info!(
  71. pdev,
  72. "pci-testdev config space read32 BAR 0: {:x}\n",
  73. config.read32(0x10)
  74. );
  75. }
  76. }
  77. impl pci::Driver for SampleDriver {
  78. type IdInfo = TestIndex;
  79. const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
  80. fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> impl PinInit<Self, Error> {
  81. pin_init::pin_init_scope(move || {
  82. let vendor = pdev.vendor_id();
  83. dev_dbg!(
  84. pdev,
  85. "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n",
  86. vendor,
  87. pdev.device_id()
  88. );
  89. pdev.enable_device_mem()?;
  90. pdev.set_master();
  91. Ok(try_pin_init!(Self {
  92. bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c"rust_driver_pci"),
  93. index: *info,
  94. _: {
  95. let bar = bar.access(pdev.as_ref())?;
  96. dev_info!(
  97. pdev,
  98. "pci-testdev data-match count: {}\n",
  99. Self::testdev(info, bar)?
  100. );
  101. Self::config_space(pdev);
  102. },
  103. pdev: pdev.into(),
  104. }))
  105. })
  106. }
  107. fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) {
  108. if let Ok(bar) = this.bar.access(pdev.as_ref()) {
  109. // Reset pci-testdev by writing a new test index.
  110. bar.write8(this.index.0, Regs::TEST);
  111. }
  112. }
  113. }
  114. #[pinned_drop]
  115. impl PinnedDrop for SampleDriver {
  116. fn drop(self: Pin<&mut Self>) {
  117. dev_dbg!(self.pdev, "Remove Rust PCI driver sample.\n");
  118. }
  119. }
  120. kernel::module_pci_driver! {
  121. type: SampleDriver,
  122. name: "rust_driver_pci",
  123. authors: ["Danilo Krummrich"],
  124. description: "Rust PCI driver",
  125. license: "GPL v2",
  126. }