device.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. use super::{CommonHeader, Header};
  2. use crate::{kernel::mem::PhysAccess as _, sync::fence::memory_barrier};
  3. use acpi::mcfg::PciConfigEntry;
  4. use alloc::sync::Arc;
  5. use core::{ops::RangeInclusive, sync::atomic::Ordering};
  6. use eonix_mm::address::PAddr;
  7. use eonix_sync::{LazyLock, Spin};
  8. use intrusive_collections::{intrusive_adapter, KeyAdapter, RBTree, RBTreeAtomicLink};
  9. pub(super) static PCIE_DEVICES: LazyLock<Spin<RBTree<PCIDeviceAdapter>>> =
  10. LazyLock::new(|| Spin::new(RBTree::new(PCIDeviceAdapter::new())));
  11. intrusive_adapter!(
  12. pub PCIDeviceAdapter = Arc<PCIDevice<'static>> : PCIDevice { link: RBTreeAtomicLink }
  13. );
  14. #[allow(dead_code)]
  15. pub struct PCIDevice<'a> {
  16. link: RBTreeAtomicLink,
  17. segment_group: SegmentGroup,
  18. config_space: ConfigSpace,
  19. pub header: Header<'a>,
  20. pub vendor_id: u16,
  21. pub device_id: u16,
  22. }
  23. #[allow(dead_code)]
  24. #[derive(Clone)]
  25. pub struct SegmentGroup {
  26. id: u16,
  27. bus_range: RangeInclusive<u8>,
  28. base_address: PAddr,
  29. }
  30. #[allow(dead_code)]
  31. #[derive(Clone)]
  32. pub struct ConfigSpace {
  33. bus: u8,
  34. device: u8,
  35. function: u8,
  36. base: PAddr,
  37. }
  38. impl SegmentGroup {
  39. pub fn from_entry(entry: &PciConfigEntry) -> Self {
  40. Self {
  41. id: entry.segment_group,
  42. bus_range: entry.bus_range.clone(),
  43. base_address: PAddr::from(entry.physical_address),
  44. }
  45. }
  46. pub fn iter(&self) -> impl Iterator<Item = ConfigSpace> + use<'_> {
  47. self.bus_range
  48. .clone()
  49. .map(move |bus| {
  50. (0..32)
  51. .map(move |device| {
  52. (0..8).map(move |function| ConfigSpace {
  53. bus,
  54. device,
  55. function,
  56. base: self.base_address
  57. + ((bus as usize) << 20)
  58. + ((device as usize) << 15)
  59. + ((function as usize) << 12),
  60. })
  61. })
  62. .flatten()
  63. })
  64. .flatten()
  65. }
  66. }
  67. impl ConfigSpace {
  68. pub fn header<'a>(&self) -> Option<Header<'a>> {
  69. let common_header = unsafe {
  70. // SAFETY: `self.base` is guaranteed to be pointing to a valid
  71. // configuration space area.
  72. self.base.as_ptr::<CommonHeader>().as_ref()
  73. };
  74. if common_header.vendor_id == 0xffff {
  75. return None;
  76. }
  77. // Bit 7 represents whether the device has multiple functions.
  78. let header_type = common_header.header_type & !(1 << 7);
  79. match header_type {
  80. 0 => Some(Header::Endpoint(unsafe {
  81. // SAFETY: `self.base` is guaranteed to be pointing to a valid
  82. // configuration space area.
  83. self.base.as_ptr().as_ref()
  84. })),
  85. 1 | 2 => unimplemented!("Header type 1 and 2"),
  86. _ => Some(Header::Unknown(unsafe {
  87. // SAFETY: `self.base` is guaranteed to be pointing to a valid
  88. // configuration space area.
  89. self.base.as_ptr().as_ref()
  90. })),
  91. }
  92. }
  93. }
  94. impl PCIDevice<'static> {
  95. pub fn new(
  96. segment_group: SegmentGroup,
  97. config_space: ConfigSpace,
  98. header: Header<'static>,
  99. ) -> Arc<Self> {
  100. let common_header = header.common_header();
  101. Arc::new(PCIDevice {
  102. link: RBTreeAtomicLink::new(),
  103. segment_group,
  104. config_space,
  105. vendor_id: common_header.vendor_id,
  106. device_id: common_header.device_id,
  107. header,
  108. })
  109. }
  110. }
  111. #[allow(dead_code)]
  112. impl PCIDevice<'_> {
  113. pub fn enable_bus_mastering(&self) {
  114. let header = self.header.common_header();
  115. header.command().fetch_or(0x04, Ordering::Relaxed);
  116. memory_barrier();
  117. }
  118. }
  119. impl<'a> KeyAdapter<'a> for PCIDeviceAdapter {
  120. type Key = u32;
  121. fn get_key(
  122. &self,
  123. value: &'a <Self::PointerOps as intrusive_collections::PointerOps>::Value,
  124. ) -> Self::Key {
  125. ((value.vendor_id as u32) << 16) | value.device_id as u32
  126. }
  127. }