1use core::{fmt::Debug, ops::Range};
2
3use crate::{
4 define::Phandle,
5 error::FdtResult,
6 node::Node,
7 read::{FdtReader, U32Array},
8 FdtError, FdtRangeIter, InterruptController,
9};
10
11pub struct Pci<'a> {
12 pub node: Node<'a>,
13}
14
15impl<'a> Pci<'a> {
16 pub fn bus_range(&self) -> Option<Range<usize>> {
17 let prop = self.node.find_property("bus-range")?;
18 let mut reader = FdtReader::new(prop.raw_value());
19 let start = reader.take_u32()?;
20 let end = reader.take_u32()?;
21
22 Some(start as usize..end as usize)
23 }
24
25 pub fn ranges(&self) -> FdtResult<impl Iterator<Item = PciRange> + 'a> {
26 let ranges = self
27 .node
28 .node_ranges()
29 .ok_or(FdtError::NotFound("ranges"))?;
30
31 let iter = ranges.iter();
32
33 Ok(PciRangeIter { iter })
34 }
35
36 pub fn child_interrupts(
37 &self,
38 bus: u8,
39 device: u8,
40 func: u8,
41 irq_pin: u32,
42 ) -> FdtResult<PciChildIrq<'a>> {
43 let mask = self.interrupt_map_mask()?;
44
45 let want0 = (bus as u32) << 16 | (device as u32) << 11 | (func as u32) << 8;
46
47 let mut want = [0; 4];
48
49 want[0] = want0 & mask[0];
50 want[3] = irq_pin & mask[3];
51
52 let mut prop = self
53 .node
54 .find_property("interrupt-map")
55 .ok_or(FdtError::NotFound("interrupt-map"))?;
56
57 while let Some(hi) = prop.data.take_u32() {
58 let _mid = prop.data.take_u32().ok_or(FdtError::Eof)?;
59 let _lo = prop.data.take_u32().ok_or(FdtError::Eof)?;
60 let irq_line = prop.data.take_u32().ok_or(FdtError::Eof)?;
61
62 let parent = Phandle::from(prop.data.take_u32().ok_or(FdtError::Eof)?);
63
64 let parent_node = self
65 .node
66 .fdt
67 .get_node_by_phandle(parent)
68 .ok_or(FdtError::NotFound("parent interrupt"))?;
69
70 let address_cell = parent_node
71 .find_property("#address-cells")
72 .map(|p| p.u32())
73 .unwrap_or_default();
74
75 for _i in 0..address_cell {
76 prop.data.take_u32().ok_or(FdtError::Eof)?;
77 }
78
79 let parent_node = InterruptController { node: parent_node };
80
81 let cell_size = parent_node.interrupt_cells();
82
83 let data = prop
84 .data
85 .take(cell_size * size_of::<u32>())
86 .ok_or(FdtError::Eof)?;
87
88 if hi & mask[0] != want[0] || irq_line != want[3] {
89 continue;
90 }
91
92 return Ok(PciChildIrq {
93 parent,
94 irqs: U32Array::new(data),
95 });
96 }
97
98 Err(FdtError::NotFound("pci child"))
99 }
100
101 fn interrupt_map_mask(&self) -> FdtResult<[u32; 4]> {
102 let prop = self
103 .node
104 .find_property("interrupt-map-mask")
105 .ok_or(FdtError::NotFound("interrupt-map-mask"))?;
106
107 let mut mask = [0u32; 4];
108 let mut data = prop.data.clone();
109
110 for one in mask.iter_mut() {
111 *one = data.take_u32().ok_or(FdtError::Eof)?;
112 }
113
114 Ok(mask)
115 }
116}
117
118pub struct PciChildIrq<'a> {
119 pub parent: Phandle,
120 pub irqs: U32Array<'a>,
121}
122
123pub struct PciRangeIter<'a> {
124 iter: FdtRangeIter<'a>,
125}
126
127impl Iterator for PciRangeIter<'_> {
128 type Item = PciRange;
129
130 fn next(&mut self) -> Option<Self::Item> {
131 let one = self.iter.next()?;
132 let mut child = one.child_bus_address();
133 let cpu_address = one.parent_bus_address().as_u64();
134 let size = one.size;
135
136 let hi = child.next().unwrap();
137 let mid = child.next().unwrap();
138 let low = child.next().unwrap();
139
140 let ss = (hi >> 24) & 0b11;
141 let prefetchable = (hi & 1 << 30) > 0;
142
143 let space = match ss {
144 0b00 => PciSpace::Configuration,
145 0b01 => PciSpace::IO,
146 0b10 => PciSpace::Memory32,
147 0b11 => PciSpace::Memory64,
148 _ => panic!(),
149 };
150
151 let child_bus_address = (mid as u64) << 32 | low as u64;
152
153 Some(PciRange {
154 space,
155 bus_address: child_bus_address,
156 cpu_address,
157 size,
158 prefetchable,
159 })
160 }
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum PciSpace {
165 Configuration,
166 IO,
167 Memory32,
168 Memory64,
169}
170
171#[derive(Clone, PartialEq, Eq)]
172pub struct PciRange {
173 pub space: PciSpace,
174 pub bus_address: u64,
175 pub cpu_address: u64,
176 pub size: u64,
177 pub prefetchable: bool,
178}
179
180impl Debug for PciRange {
234 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
235 write!(f, "PciRange {{ space: {:?}, child_bus_address: {:#x}, parent_bus_address: {:#x}, size: {:#x}, prefetchable: {}}}",
236 self.space, self.bus_address, self.cpu_address, self.size, self.prefetchable)
237 }
238}