1use core::ops::{Deref, Range};
2
3use alloc::vec::Vec;
4use fdt_raw::{FdtError, Phandle, data::U32Iter};
5use log::debug;
6
7use crate::node::gerneric::NodeRefGen;
8
9#[derive(Clone, Debug, PartialEq)]
10pub enum PciSpace {
11 IO,
12 Memory32,
13 Memory64,
14}
15
16#[derive(Clone, Debug, PartialEq)]
17pub struct PciRange {
18 pub space: PciSpace,
19 pub bus_address: u64,
20 pub cpu_address: u64,
21 pub size: u64,
22 pub prefetchable: bool,
23}
24
25#[derive(Clone, Debug)]
26pub struct PciInterruptMap {
27 pub child_address: Vec<u32>,
28 pub child_irq: Vec<u32>,
29 pub interrupt_parent: Phandle,
30 pub parent_irq: Vec<u32>,
31}
32
33#[derive(Clone, Debug, PartialEq)]
34pub struct PciInterruptInfo {
35 pub irqs: Vec<u32>,
36}
37
38#[derive(Clone, Debug)]
39pub struct NodeRefPci<'a> {
40 pub node: NodeRefGen<'a>,
41}
42
43impl<'a> NodeRefPci<'a> {
44 pub fn try_from(node: NodeRefGen<'a>) -> Result<Self, NodeRefGen<'a>> {
46 if node.device_type() == Some("pci") {
47 Ok(Self { node })
48 } else {
49 Err(node)
50 }
51 }
52
53 pub fn interrupt_cells(&self) -> u32 {
54 self.find_property("#interrupt-cells")
55 .and_then(|prop| prop.get_u32())
56 .unwrap_or(1) }
58
59 pub fn interrupt_map_mask(&self) -> Option<U32Iter<'_>> {
61 self.find_property("interrupt-map-mask")
62 .map(|prop| prop.get_u32_iter())
63 }
64
65 pub fn bus_range(&self) -> Option<Range<u32>> {
67 self.find_property("bus-range").and_then(|prop| {
68 let mut data = prop.get_u32_iter();
69 let start = data.next()?;
70 let end = data.next()?;
71
72 Some(start..end)
73 })
74 }
75
76 pub fn ranges(&self) -> Option<Vec<PciRange>> {
78 let prop = self.find_property("ranges")?;
79
80 let mut data = prop.as_reader();
81
82 let mut ranges = Vec::new();
83
84 let parent_addr_cells = self.ctx.parent_address_cells() as usize;
89 let size_cells = self.size_cells().unwrap_or(2) as usize;
90
91 while let Some(pci_hi) = data.read_u32() {
92 let bus_address = data.read_u64()?;
94
95 let parent_addr = data.read_cells(parent_addr_cells)?;
97
98 let size = data.read_cells(size_cells)?;
100
101 let (space, prefetchable) = self.decode_pci_address_space(pci_hi);
103
104 ranges.push(PciRange {
105 space,
106 bus_address,
107 cpu_address: parent_addr,
108 size,
109 prefetchable,
110 });
111 }
112
113 Some(ranges)
114 }
115
116 fn decode_pci_address_space(&self, pci_hi: u32) -> (PciSpace, bool) {
118 let space_code = (pci_hi >> 24) & 0x03;
122 let prefetchable = (pci_hi >> 30) & 0x01 == 1;
123
124 let space = match space_code {
125 1 => PciSpace::IO,
126 2 => PciSpace::Memory32,
127 3 => PciSpace::Memory64,
128 _ => PciSpace::Memory32, };
130
131 (space, prefetchable)
132 }
133
134 pub fn child_interrupts(
137 &self,
138 bus: u8,
139 device: u8,
140 function: u8,
141 interrupt_pin: u8,
142 ) -> Result<PciInterruptInfo, FdtError> {
143 let interrupt_map = self.interrupt_map()?;
145
146 let mask: Vec<u32> = self
148 .interrupt_map_mask()
149 .ok_or(FdtError::NotFound)?
150 .collect();
151
152 let child_addr_high = ((bus as u32 & 0xff) << 16)
155 | ((device as u32 & 0x1f) << 11)
156 | ((function as u32 & 0x7) << 8);
157 let child_addr_mid = 0u32;
158 let child_addr_low = 0u32;
159
160 let child_addr_cells = self.address_cells().unwrap_or(3) as usize;
161 let child_irq_cells = self.interrupt_cells() as usize;
162
163 let encoded_address = [child_addr_high, child_addr_mid, child_addr_low];
164 let mut masked_child_address = Vec::with_capacity(child_addr_cells);
165
166 for (idx, value) in encoded_address.iter().take(child_addr_cells).enumerate() {
168 let mask_value = mask.get(idx).copied().unwrap_or(0xffff_ffff);
169 masked_child_address.push(value & mask_value);
170 }
171
172 let remaining = child_addr_cells.saturating_sub(encoded_address.len());
174 masked_child_address.extend(core::iter::repeat_n(0, remaining));
175
176 let encoded_irq = [interrupt_pin as u32];
177 let mut masked_child_irq = Vec::with_capacity(child_irq_cells);
178
179 for (idx, value) in encoded_irq.iter().take(child_irq_cells).enumerate() {
181 let mask_value = mask
182 .get(child_addr_cells + idx)
183 .copied()
184 .unwrap_or(0xffff_ffff);
185 masked_child_irq.push(value & mask_value);
186 }
187
188 let remaining_irq = child_irq_cells.saturating_sub(encoded_irq.len());
190 masked_child_irq.extend(core::iter::repeat_n(0, remaining_irq));
191
192 for mapping in &interrupt_map {
194 if mapping.child_address == masked_child_address
195 && mapping.child_irq == masked_child_irq
196 {
197 return Ok(PciInterruptInfo {
198 irqs: mapping.parent_irq.clone(),
199 });
200 }
201 }
202
203 let simple_irq = (device as u32 * 4 + interrupt_pin as u32) % 32;
205 Ok(PciInterruptInfo {
206 irqs: vec![simple_irq],
207 })
208 }
209
210 pub fn interrupt_map(&self) -> Result<Vec<PciInterruptMap>, FdtError> {
212 let prop = self
213 .find_property("interrupt-map")
214 .ok_or(FdtError::NotFound)?;
215
216 let mask: Vec<u32> = self
218 .interrupt_map_mask()
219 .ok_or(FdtError::NotFound)?
220 .collect();
221
222 let mut data = prop.as_reader();
223 let mut mappings = Vec::new();
224
225 let child_addr_cells = self.address_cells().unwrap_or(3) as usize;
228 let child_irq_cells = self.interrupt_cells() as usize;
229
230 loop {
231 let mut child_address = Vec::with_capacity(child_addr_cells);
233 for _ in 0..child_addr_cells {
234 match data.read_u32() {
235 Some(v) => child_address.push(v),
236 None => return Ok(mappings), }
238 }
239
240 let mut child_irq = Vec::with_capacity(child_irq_cells);
242 for _ in 0..child_irq_cells {
243 match data.read_u32() {
244 Some(v) => child_irq.push(v),
245 None => return Ok(mappings),
246 }
247 }
248
249 let interrupt_parent_raw = match data.read_u32() {
251 Some(v) => v,
252 None => return Ok(mappings),
253 };
254 let interrupt_parent = Phandle::from(interrupt_parent_raw);
255
256 debug!(
257 "Looking for interrupt parent phandle: 0x{:x} (raw: {})",
258 interrupt_parent.raw(),
259 interrupt_parent_raw
260 );
261 debug!(
262 "Context phandle_map keys: {:?}",
263 self.ctx
264 .phandle_map
265 .keys()
266 .map(|p| format!("0x{:x}", p.raw()))
267 .collect::<Vec<_>>()
268 );
269
270 let (parent_addr_cells, parent_irq_cells) =
273 if let Some(irq_parent) = self.ctx.find_by_phandle(interrupt_parent) {
274 debug!("Found interrupt parent: {:?}", irq_parent.name);
275
276 let addr_cells = irq_parent.address_cells().unwrap_or(0) as usize;
278
279 let irq_cells = irq_parent
280 .get_property("#interrupt-cells")
281 .and_then(|p| p.get_u32())
282 .unwrap_or(3) as usize;
283 debug!(
284 "irq_parent addr_cells: {}, irq_cells: {}",
285 addr_cells, irq_cells
286 );
287 (addr_cells, irq_cells)
288 } else {
289 debug!(
290 "Interrupt parent phandle 0x{:x} NOT FOUND in context!",
291 interrupt_parent.raw()
292 );
293 (0, 3)
295 };
296
297 for _ in 0..parent_addr_cells {
299 if data.read_u32().is_none() {
300 return Ok(mappings);
301 }
302 }
303
304 let mut parent_irq = Vec::with_capacity(parent_irq_cells);
306 for _ in 0..parent_irq_cells {
307 match data.read_u32() {
308 Some(v) => parent_irq.push(v),
309 None => return Ok(mappings),
310 }
311 }
312
313 let masked_address: Vec<u32> = child_address
315 .iter()
316 .enumerate()
317 .map(|(i, value)| {
318 let mask_value = mask.get(i).copied().unwrap_or(0xffff_ffff);
319 value & mask_value
320 })
321 .collect();
322 let masked_irq: Vec<u32> = child_irq
323 .iter()
324 .enumerate()
325 .map(|(i, value)| {
326 let mask_value = mask
327 .get(child_addr_cells + i)
328 .copied()
329 .unwrap_or(0xffff_ffff);
330 value & mask_value
331 })
332 .collect();
333
334 mappings.push(PciInterruptMap {
335 child_address: masked_address,
336 child_irq: masked_irq,
337 interrupt_parent,
338 parent_irq,
339 });
340 }
341 }
342}
343
344impl<'a> Deref for NodeRefPci<'a> {
345 type Target = NodeRefGen<'a>;
346
347 fn deref(&self) -> &Self::Target {
348 &self.node
349 }
350}