1use alloc::vec::Vec;
2use core::hint::spin_loop;
3
4use crate::{
5 Endpoint, PciAddress, PciConfigSpace, PciHeaderBase, PciPciBridge, chip::PcieController,
6};
7
8const MAX_DEVICE: u8 = 31;
9const MAX_FUNCTION: u8 = 7;
10
11pub fn enumerate_by_controller<'a>(
12 controller: &'a mut PcieController,
13 range: Option<core::ops::Range<usize>>,
14) -> impl Iterator<Item = Endpoint> + 'a {
15 enumerate_by_controller_with_info(controller, range).map(|item| item.endpoint)
16}
17
18pub fn enumerate_by_controller_with_info<'a>(
19 controller: &'a mut PcieController,
20 range: Option<core::ops::Range<usize>>,
21) -> impl Iterator<Item = EnumeratedEndpoint> + 'a {
22 let range = range.unwrap_or(0..0x100);
23
24 PciIterator {
25 root: controller,
26 segment: 0,
27 bus_max: (range.end - 1) as _,
28 function: 0,
29 is_mulitple_function: false,
30 is_finish: false,
31 stack: alloc::vec![Bridge::root(range.start as _)],
32 }
33}
34
35#[derive(Debug)]
36pub struct EnumeratedEndpoint {
37 pub endpoint: Endpoint,
38 pub intx_route: Option<PciIntxRoute>,
39}
40
41#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct PciIntxRoute {
43 pub root_device: u8,
44 pub root_function: u8,
45 pub root_pin: u8,
46}
47
48pub(crate) struct PciIterator<'a> {
49 root: &'a mut PcieController,
50 segment: u16,
51 stack: Vec<Bridge>,
52 bus_max: u8,
53 function: u8,
54 is_mulitple_function: bool,
55 is_finish: bool,
56}
57
58impl<'a> Iterator for PciIterator<'a> {
59 type Item = EnumeratedEndpoint;
60
61 fn next(&mut self) -> Option<Self::Item> {
62 while !self.is_finish {
63 if let Some(value) = self.get_current_valid() {
64 match value {
65 PciConfigSpace::PciPciBridge(pci_pci_bridge) => {
66 self.next(Some(pci_pci_bridge));
67 }
68 PciConfigSpace::Endpoint(ep) => {
69 let intx_route = self.intx_route_for_endpoint(&ep);
70 let item = EnumeratedEndpoint {
71 endpoint: ep,
72 intx_route,
73 };
74 self.next(None);
75 return Some(item);
76 }
77 PciConfigSpace::CardBusBridge(_) | PciConfigSpace::Unknown(_) => {
78 self.next(None);
80 }
81 }
82 } else {
83 self.next(None);
84 }
85 }
86 None
87 }
88}
89
90impl<'a> PciIterator<'a> {
91 fn get_current_valid(&mut self) -> Option<PciConfigSpace> {
92 let address = self.address();
93 let header_base = PciHeaderBase::new(self.root, address)?;
94 self.is_mulitple_function = header_base.has_multiple_functions();
95
96 match header_base.header_type() {
97 pci_types::HeaderType::Endpoint => {
98 let bl = self.root.bar_allocator.as_mut();
99 let ep = Endpoint::new(header_base, bl);
100 Some(PciConfigSpace::Endpoint(ep))
101 }
102 pci_types::HeaderType::PciPciBridge => {
103 let mut bridge = PciPciBridge::new(header_base);
104 let primary_bus = address.bus();
105 let secondary_bus;
106
107 if let Some(parent) = self.stack.last_mut() {
108 if parent.bridge.subordinate_bus_number() == self.bus_max {
109 return None;
110 }
111
112 secondary_bus = parent.bridge.subordinate_bus_number() + 1;
113 } else {
114 panic!("no parent");
115 }
116 let subordinate_bus = secondary_bus;
117 bridge.update_bus_number(|mut bus| {
118 bus.primary = primary_bus;
119 bus.secondary = secondary_bus;
120 bus.subordinate = subordinate_bus;
121 bus
122 });
123
124 Some(PciConfigSpace::PciPciBridge(bridge))
125 }
126 pci_types::HeaderType::CardBusBridge => todo!(),
127 pci_types::HeaderType::Unknown(_) => todo!(),
128 _ => unreachable!(),
129 }
130 }
131
132 fn address(&self) -> PciAddress {
133 let parent = self.stack.last().unwrap();
134 let bus = parent.bridge.secondary_bus_number();
135 let device = parent.device;
136
137 PciAddress::new(self.segment, bus, device, self.function)
138 }
139
140 fn intx_route_for_endpoint(&self, endpoint: &Endpoint) -> Option<PciIntxRoute> {
141 root_intx_route(
142 endpoint.address(),
143 endpoint.interrupt_pin(),
144 self.stack.iter().skip(1).map(|bridge| BridgeAddress {
145 device: bridge.parent_device,
146 function: bridge.parent_function,
147 }),
148 )
149 }
150
151 fn is_next_function_max(&mut self) -> bool {
153 if self.is_mulitple_function {
154 if self.function == MAX_FUNCTION {
155 self.function = 0;
156 true
157 } else {
158 self.function += 1;
159 false
160 }
161 } else {
162 self.function = 0;
163 true
164 }
165 }
166
167 fn next_device_not_ok(&mut self) -> bool {
169 if let Some(parent) = self.stack.last_mut() {
170 if parent.device == MAX_DEVICE {
171 if let Some(parent) = self.stack.pop() {
172 self.is_finish = parent.bridge.subordinate_bus_number() == self.bus_max;
173
174 self.function = 0;
176 return true;
177 } else {
178 self.is_finish = true;
179 }
180 } else {
181 parent.device += 1;
182 }
183 } else {
184 self.is_finish = true;
185 }
186
187 false
188 }
189
190 fn next(&mut self, current_bridge: Option<PciPciBridge>) {
191 if let Some(bridge) = current_bridge {
192 for parent in &mut self.stack {
193 parent.bridge.update_bus_number(|mut bus| {
196 bus.subordinate += 1;
197 bus
198 });
199 }
200
201 let address = bridge.address();
202 self.stack.push(Bridge {
203 bridge,
204 device: 0,
205 parent_device: address.device(),
206 parent_function: address.function(),
207 });
208
209 self.function = 0;
210 return;
211 }
212
213 if self.is_next_function_max() {
214 while self.next_device_not_ok() {
215 spin_loop();
216 }
217 }
218 }
219}
220
221struct Bridge {
222 bridge: PciPciBridge,
223 device: u8,
224 parent_device: u8,
225 parent_function: u8,
226}
227
228impl Bridge {
229 fn root(bus_start: u8) -> Self {
230 Self {
231 bridge: PciPciBridge::root(),
232 device: bus_start,
233 parent_device: 0,
234 parent_function: 0,
235 }
236 }
237}
238
239const fn swizzle_interrupt_pin(interrupt_pin: u8, device: u8) -> Option<u8> {
240 if interrupt_pin == 0 || interrupt_pin > 4 {
241 return None;
242 }
243 Some(((interrupt_pin - 1 + (device & 0x3)) % 4) + 1)
244}
245
246#[derive(Clone, Copy)]
247struct BridgeAddress {
248 device: u8,
249 function: u8,
250}
251
252fn root_intx_route(
253 endpoint: PciAddress,
254 interrupt_pin: u8,
255 bridges_from_root: impl DoubleEndedIterator<Item = BridgeAddress>,
256) -> Option<PciIntxRoute> {
257 let mut pin = interrupt_pin;
258 if !(1..=4).contains(&pin) {
259 return None;
260 }
261
262 let mut device = endpoint.device();
263 let mut function = endpoint.function();
264 for bridge in bridges_from_root.rev() {
265 pin = swizzle_interrupt_pin(pin, device)?;
266 device = bridge.device;
267 function = bridge.function;
268 }
269
270 Some(PciIntxRoute {
271 root_device: device,
272 root_function: function,
273 root_pin: pin,
274 })
275}
276
277#[cfg(test)]
278mod tests {
279 use super::{BridgeAddress, PciIntxRoute, root_intx_route, swizzle_interrupt_pin};
280 use crate::PciAddress;
281
282 #[test]
283 fn intx_swizzle_uses_linux_slot_rotation() {
284 assert_eq!(swizzle_interrupt_pin(1, 0), Some(1));
285 assert_eq!(swizzle_interrupt_pin(1, 1), Some(2));
286 assert_eq!(swizzle_interrupt_pin(1, 2), Some(3));
287 assert_eq!(swizzle_interrupt_pin(1, 3), Some(4));
288 assert_eq!(swizzle_interrupt_pin(4, 1), Some(1));
289 }
290
291 #[test]
292 fn intx_swizzle_rejects_absent_or_invalid_pins() {
293 assert_eq!(swizzle_interrupt_pin(0, 1), None);
294 assert_eq!(swizzle_interrupt_pin(5, 1), None);
295 }
296
297 #[test]
298 fn root_endpoint_uses_its_own_device_function_and_pin() {
299 let route = root_intx_route(PciAddress::new(0, 0, 5, 2), 3, [].into_iter());
300
301 assert_eq!(
302 route,
303 Some(PciIntxRoute {
304 root_device: 5,
305 root_function: 2,
306 root_pin: 3,
307 })
308 );
309 }
310
311 #[test]
312 fn bridge_endpoint_uses_parent_bridge_slot_and_swizzled_pin() {
313 let route = root_intx_route(
314 PciAddress::new(0, 1, 3, 0),
315 1,
316 [BridgeAddress {
317 device: 2,
318 function: 0,
319 }]
320 .into_iter(),
321 );
322
323 assert_eq!(
324 route,
325 Some(PciIntxRoute {
326 root_device: 2,
327 root_function: 0,
328 root_pin: 4,
329 })
330 );
331 }
332
333 #[test]
334 fn nested_bridge_endpoint_swizzles_at_each_level() {
335 let route = root_intx_route(
336 PciAddress::new(0, 2, 1, 0),
337 2,
338 [
339 BridgeAddress {
340 device: 4,
341 function: 1,
342 },
343 BridgeAddress {
344 device: 3,
345 function: 0,
346 },
347 ]
348 .into_iter(),
349 );
350
351 assert_eq!(
352 route,
353 Some(PciIntxRoute {
354 root_device: 4,
355 root_function: 1,
356 root_pin: 2,
357 })
358 );
359 }
360}