1use alloc::{
2 collections::{BTreeMap, BTreeSet},
3 format,
4 rc::Rc,
5 string::{String, ToString},
6 vec::Vec,
7};
8use core::{ptr::NonNull, str::FromStr};
9
10use acpi::{
11 AcpiError, AcpiTables, Handler, PhysicalMapping,
12 address::{AddressSpace, GenericAddress},
13 aml::{
14 AmlError, Interpreter,
15 namespace::{AmlName, NamespaceLevelKind},
16 object::{FieldUnit, FieldUnitKind, FieldUpdateRule, Object, ObjectType},
17 op_region::{OpRegion, RegionSpace},
18 pci_routing::{IrqDescriptor, PciRoutingTable, Pin},
19 resource::{
20 AddressSpaceResourceType, InterruptPolarity, InterruptTrigger, Resource,
21 resource_descriptor_list,
22 },
23 },
24 platform::{
25 AcpiPlatform,
26 interrupt::{InterruptModel, Polarity, TriggerMode},
27 pci::PciConfigRegions,
28 },
29 sdt::spcr::{Spcr, SpcrInterfaceType},
30};
31use ax_kspin::SpinNoPreempt as Mutex;
32pub use rdif_base::irq::{AcpiGsiController, AcpiGsiRoute, AcpiIrqPolarity, AcpiIrqTrigger};
33use spin::Once;
34
35use crate::{
36 DeviceId, PlatformDevice,
37 error::DriverError,
38 probe::{
39 OnProbeError, ProbeError,
40 pci::{PciAddress, PciInfo, PciIntxRoute},
41 },
42 register::{DriverRegister, ProbeKind},
43};
44
45pub const PCI_INTX_VECTOR_BASE: usize = 0x30;
46const LOONGARCH_PCH_PIC_GSI_COUNT: u16 = 256;
47const PCI_ROOT_FALLBACK_PATHS: &[&str] = &["\\_SB.PCI0", "\\_SB.PCI1", "\\_SB.PC00", "\\_SB.PC01"];
48
49static SYSTEM: Once<System> = Once::new();
50static NULL_LOCK: Mutex<()> = Mutex::new(());
51
52#[derive(Clone, Copy)]
53pub struct AcpiRoot {
54 pub rsdp: usize,
55 pub phys_to_virt: fn(usize) -> *mut u8,
56}
57
58impl core::fmt::Debug for AcpiRoot {
59 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60 f.debug_struct("AcpiRoot")
61 .field("rsdp", &self.rsdp)
62 .finish_non_exhaustive()
63 }
64}
65
66impl AcpiRoot {
67 pub const fn new(rsdp: usize, phys_to_virt: fn(usize) -> *mut u8) -> Self {
68 Self { rsdp, phys_to_virt }
69 }
70
71 pub const fn identity(rsdp: usize) -> Self {
72 Self::new(rsdp, identity_phys_to_virt)
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub struct AcpiId {
78 pub hid: &'static str,
79 pub cids: &'static [&'static str],
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub struct AcpiPciEcam {
84 pub segment_group: u16,
85 pub bus_start: u8,
86 pub bus_end: u8,
87 pub base_address: u64,
88}
89
90impl AcpiPciEcam {
91 pub fn size(&self) -> usize {
92 let buses = usize::from(self.bus_end.saturating_sub(self.bus_start)) + 1;
93 buses << 20
94 }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub struct AcpiIoApic {
99 pub id: u8,
100 pub address: u32,
101 pub gsi_base: u32,
102 pub redirection_entries: u8,
103}
104
105impl AcpiIoApic {
106 fn gsi_source(self) -> AcpiGsiSource {
107 AcpiGsiSource {
108 controller: AcpiGsiController::IoApic,
109 controller_id: u16::from(self.id),
110 controller_address: u64::from(self.address),
111 gsi_base: self.gsi_base,
112 gsi_count: u16::from(self.redirection_entries),
113 }
114 }
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub struct AcpiPchPic {
119 pub id: u16,
120 pub address: u64,
121 pub mmio_size: u16,
122 pub gsi_count: u16,
123 pub gsi_base: u32,
124}
125
126impl AcpiPchPic {
127 fn gsi_source(self) -> AcpiGsiSource {
128 AcpiGsiSource {
129 controller: AcpiGsiController::PchPic,
130 controller_id: self.id,
131 controller_address: self.address,
132 gsi_base: self.gsi_base,
133 gsi_count: self.gsi_count,
134 }
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139struct AcpiGsiSource {
140 controller: AcpiGsiController,
141 controller_id: u16,
142 controller_address: u64,
143 gsi_base: u32,
144 gsi_count: u16,
145}
146
147impl AcpiGsiSource {
148 fn contains_gsi(self, gsi: u32) -> bool {
149 let start = self.gsi_base;
150 let end = start.saturating_add(u32::from(self.gsi_count));
151 (start..end).contains(&gsi)
152 }
153
154 fn route(
155 self,
156 gsi: u32,
157 trigger: AcpiIrqTrigger,
158 polarity: AcpiIrqPolarity,
159 ) -> Option<AcpiGsiRoute> {
160 let controller_input = u8::try_from(gsi.checked_sub(self.gsi_base)?).ok()?;
161 Some(AcpiGsiRoute {
162 gsi,
163 vector: PCI_INTX_VECTOR_BASE + gsi as usize,
164 controller: self.controller,
165 controller_id: self.controller_id,
166 controller_address: self.controller_address,
167 controller_input,
168 trigger,
169 polarity,
170 })
171 }
172}
173
174#[derive(Debug, Clone)]
175pub struct AcpiRouting {
176 io_apics: Vec<AcpiIoApic>,
177 pch_pics: Vec<AcpiPchPic>,
178 isa_overrides: Vec<AcpiIsaIrqOverride>,
179}
180
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub struct AcpiIsaIrqOverride {
183 pub source: u8,
184 pub gsi: u32,
185 pub trigger: AcpiIrqTrigger,
186 pub polarity: AcpiIrqPolarity,
187}
188
189impl AcpiRouting {
190 pub const fn new() -> Self {
191 Self {
192 io_apics: Vec::new(),
193 pch_pics: Vec::new(),
194 isa_overrides: Vec::new(),
195 }
196 }
197
198 pub fn add_io_apic(&mut self, io_apic: AcpiIoApic) {
199 self.io_apics.push(io_apic);
200 }
201
202 pub fn io_apics(&self) -> &[AcpiIoApic] {
203 &self.io_apics
204 }
205
206 pub fn add_pch_pic(&mut self, pch_pic: AcpiPchPic) {
207 self.pch_pics.push(pch_pic);
208 }
209
210 pub fn pch_pics(&self) -> &[AcpiPchPic] {
211 &self.pch_pics
212 }
213
214 pub fn add_isa_irq_override(&mut self, irq_override: AcpiIsaIrqOverride) {
215 self.isa_overrides.push(irq_override);
216 }
217
218 pub fn resolve_gsi(&self, gsi: u32) -> Option<AcpiGsiRoute> {
219 self.gsi_sources()
220 .find(|source| source.contains_gsi(gsi))?
221 .route(gsi, self.default_trigger(gsi), self.default_polarity(gsi))
222 }
223
224 fn gsi_sources(&self) -> impl Iterator<Item = AcpiGsiSource> + '_ {
225 self.io_apics
226 .iter()
227 .copied()
228 .map(AcpiIoApic::gsi_source)
229 .chain(self.pch_pics.iter().copied().map(AcpiPchPic::gsi_source))
230 }
231
232 pub fn resolve_vector(&self, vector: usize) -> Option<AcpiGsiRoute> {
233 let gsi = vector.checked_sub(PCI_INTX_VECTOR_BASE)?;
234 self.resolve_gsi(gsi as u32)
235 }
236
237 fn default_trigger(&self, gsi: u32) -> AcpiIrqTrigger {
238 self.isa_overrides
239 .iter()
240 .find(|irq_override| irq_override.gsi == gsi)
241 .map(|irq_override| irq_override.trigger)
242 .unwrap_or(if gsi < 16 {
243 AcpiIrqTrigger::Edge
244 } else {
245 AcpiIrqTrigger::Level
246 })
247 }
248
249 fn default_polarity(&self, gsi: u32) -> AcpiIrqPolarity {
250 self.isa_overrides
251 .iter()
252 .find(|irq_override| irq_override.gsi == gsi)
253 .map(|irq_override| irq_override.polarity)
254 .unwrap_or(if gsi < 16 {
255 AcpiIrqPolarity::ActiveHigh
256 } else {
257 AcpiIrqPolarity::ActiveLow
258 })
259 }
260}
261
262impl Default for AcpiRouting {
263 fn default() -> Self {
264 Self::new()
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use alloc::{
271 string::{String, ToString},
272 sync::Arc,
273 vec::Vec,
274 };
275 use core::str::FromStr;
276
277 use acpi::{
278 address::{AddressSpace, GenericAddress},
279 aml::{
280 Interpreter,
281 namespace::{AmlName, NamespaceLevelKind},
282 object::Object,
283 pci_routing::IrqDescriptor,
284 resource::{InterruptPolarity, InterruptTrigger},
285 },
286 registers::{FixedRegisters, Pm1ControlRegisterBlock, Pm1EventRegisterBlock},
287 };
288
289 use super::{
290 AcpiGsiController, AcpiHandler, AcpiId, AcpiIoApic, AcpiIrqPolarity, AcpiIrqTrigger,
291 AcpiIsaIrqOverride, AcpiPchPic, AcpiResourceRange, AcpiRoot, AcpiRouting, LinkIrqResource,
292 LinkIrqResourceKind, Mutex, PciLinkAllocator, System, irq_descriptor_gsi,
293 is_buffer_field_to_field_unit_store_gap, pci_irq_descriptor_gsi,
294 pci_link_irq_field_candidates, route_with_irq_descriptor_flags, select_pci_link_irq,
295 };
296 use crate::register::{DriverRegister, ProbeKind, ProbeLevel, ProbePriority};
297
298 fn test_fixed_registers(handler: &AcpiHandler) -> Arc<FixedRegisters<AcpiHandler>> {
299 let event_gas = GenericAddress {
300 address_space: AddressSpace::SystemIo,
301 bit_width: 32,
302 bit_offset: 0,
303 access_size: 3,
304 address: 0x1000,
305 };
306 let control_gas = GenericAddress {
307 address_space: AddressSpace::SystemIo,
308 bit_width: 16,
309 bit_offset: 0,
310 access_size: 2,
311 address: 0x1004,
312 };
313 Arc::new(FixedRegisters {
314 pm1_event_registers: Pm1EventRegisterBlock {
315 pm1_event_length: 4,
316 pm1a: unsafe { acpi::address::MappedGas::map_gas(event_gas, handler).unwrap() },
317 pm1b: None,
318 },
319 pm1_control_registers: Pm1ControlRegisterBlock {
320 pm1a: unsafe { acpi::address::MappedGas::map_gas(control_gas, handler).unwrap() },
321 pm1b: None,
322 },
323 })
324 }
325
326 fn interpreter_with_devices(handler: AcpiHandler) -> Interpreter<AcpiHandler> {
327 let interpreter =
328 Interpreter::new(handler.clone(), 2, test_fixed_registers(&handler), None);
329 {
330 let mut namespace = interpreter.namespace.lock();
331 let pnp = AmlName::from_str("\\_SB.RTC0").unwrap();
332 namespace
333 .add_level(pnp.clone(), NamespaceLevelKind::Device)
334 .unwrap();
335 namespace
336 .insert(
337 AmlName::from_str("_HID").unwrap().resolve(&pnp).unwrap(),
338 Object::Integer(0x000b_d041).wrap(),
339 )
340 .unwrap();
341 namespace
342 .insert(
343 AmlName::from_str("_CRS").unwrap().resolve(&pnp).unwrap(),
344 Object::Buffer(Vec::from([
345 0x47, 0x01, 0x70, 0x00, 0x70, 0x00, 0x01, 0x08, 0x22, 0x00, 0x01, 0x79,
346 0x00,
347 ]))
348 .wrap(),
349 )
350 .unwrap();
351
352 let loon = AmlName::from_str("\\_SB.LRTC").unwrap();
353 namespace
354 .add_level(loon.clone(), NamespaceLevelKind::Device)
355 .unwrap();
356 namespace
357 .insert(
358 AmlName::from_str("_HID").unwrap().resolve(&loon).unwrap(),
359 Object::String(String::from("LOON0001")).wrap(),
360 )
361 .unwrap();
362 namespace
363 .insert(
364 AmlName::from_str("_CRS").unwrap().resolve(&loon).unwrap(),
365 Object::Buffer(Vec::from([
366 0x86, 0x09, 0x00, 0x01, 0x00, 0x01, 0x0d, 0x10, 0x00, 0x01, 0x00, 0x00,
367 0x79, 0x00,
368 ]))
369 .wrap(),
370 )
371 .unwrap();
372 }
373 interpreter
374 }
375
376 fn test_system() -> System {
377 let handler = AcpiHandler::new(AcpiRoot::identity(0x1000), Vec::new());
378 let mut routing = AcpiRouting::new();
379 routing.add_io_apic(AcpiIoApic {
380 id: 0,
381 address: 0xfec0_0000,
382 gsi_base: 0,
383 redirection_entries: 24,
384 });
385 System {
386 ecam_regions: Vec::new(),
387 routing,
388 interpreter: interpreter_with_devices(handler.clone()),
389 handler,
390 pci: None,
391 probed_names: Mutex::new(alloc::collections::BTreeSet::new()),
392 populated_paths: Mutex::new(alloc::collections::BTreeMap::new()),
393 populated_resources: Mutex::new(alloc::collections::BTreeMap::new()),
394 }
395 }
396
397 static LAST_PATH: Mutex<Option<String>> = Mutex::new(None);
398
399 fn probe_rtc(probe: super::ProbeAcpi<'_>) -> Result<(), crate::probe::OnProbeError> {
400 let info = probe.info();
401 assert_eq!(info.hid(), Some("PNP0B00"));
402 assert_eq!(
403 info.io_ranges(),
404 &[AcpiResourceRange {
405 base: 0x70,
406 size: 8,
407 }]
408 );
409 assert_eq!(
410 info.irq_routes()
411 .iter()
412 .map(|route| route.gsi)
413 .collect::<Vec<_>>(),
414 Vec::from([8])
415 );
416 *LAST_PATH.lock() = Some(info.path.to_string());
417 Ok(())
418 }
419
420 static RTC_REGISTER: DriverRegister = DriverRegister {
421 name: "test acpi rtc",
422 level: ProbeLevel::PostKernel,
423 priority: ProbePriority::DEFAULT,
424 probe_kinds: &[ProbeKind::Acpi {
425 ids: &[AcpiId {
426 hid: "PNP0B00",
427 cids: &[],
428 }],
429 on_probe: probe_rtc,
430 }],
431 };
432
433 #[test]
434 fn acpi_probe_matches_namespace_device_and_exposes_io_and_irq_resources() {
435 let system = test_system();
436
437 let results = system.probe_register(&RTC_REGISTER).unwrap();
438
439 assert_eq!(results.len(), 1);
440 assert!(results.into_iter().all(|result| result.is_ok()));
441 assert_eq!(LAST_PATH.lock().as_deref(), Some("\\_SB_.RTC0"));
442 }
443
444 #[test]
445 fn acpi_info_exposes_loongson_memory_resource() {
446 let system = test_system();
447 let info = system
448 .device_infos_for_ids(&[AcpiId {
449 hid: "LOON0001",
450 cids: &[],
451 }])
452 .unwrap()
453 .into_iter()
454 .next()
455 .expect("LOON0001 device should be discovered");
456
457 assert_eq!(info.hid.as_deref(), Some("LOON0001"));
458 assert_eq!(
459 info.memory_ranges.as_slice(),
460 &[AcpiResourceRange {
461 base: 0x100d_0100,
462 size: 0x100,
463 }]
464 );
465 }
466
467 #[test]
468 fn acpi_eisa_integer_ids_decode_to_hid_strings() {
469 assert_eq!(
470 super::decode_eisa_id(0x000b_d041).as_deref(),
471 Some("PNP0B00")
472 );
473 assert_eq!(
474 super::decode_eisa_id(0x030a_d041).as_deref(),
475 Some("PNP0A03")
476 );
477 assert_eq!(
478 super::decode_eisa_id(0x080a_d041).as_deref(),
479 Some("PNP0A08")
480 );
481 }
482
483 #[test]
484 fn ioapic_routes_map_gsi_to_stable_vector() {
485 let mut routing = AcpiRouting::new();
486 routing.add_io_apic(AcpiIoApic {
487 id: 0,
488 address: 0xfec0_0000,
489 gsi_base: 0,
490 redirection_entries: 24,
491 });
492
493 let legacy_irq = routing
494 .resolve_gsi(4)
495 .expect("legacy ISA GSI 4 should be handled by the IOAPIC");
496 assert_eq!(legacy_irq.vector, 0x34);
497 assert_eq!(legacy_irq.controller_input, 4);
498 assert_eq!(legacy_irq.trigger, AcpiIrqTrigger::Edge);
499 assert_eq!(legacy_irq.polarity, AcpiIrqPolarity::ActiveHigh);
500
501 let irq = routing
502 .resolve_gsi(16)
503 .expect("gsi 16 should be handled by the IOAPIC");
504 assert_eq!(irq.gsi, 16);
505 assert_eq!(irq.controller, AcpiGsiController::IoApic);
506 assert_eq!(irq.controller_id, 0);
507 assert_eq!(irq.controller_address, 0xfec0_0000);
508 assert_eq!(irq.controller_input, 16);
509 assert_eq!(irq.vector, 0x40);
510 assert_eq!(irq.trigger, AcpiIrqTrigger::Level);
511 assert_eq!(irq.polarity, AcpiIrqPolarity::ActiveLow);
512 assert!(routing.resolve_gsi(24).is_none());
513 }
514
515 #[test]
516 fn pci_link_irq_can_route_to_legacy_ioapic_gsi() {
517 let mut routing = AcpiRouting::new();
518 routing.add_io_apic(AcpiIoApic {
519 id: 0,
520 address: 0xfec0_0000,
521 gsi_base: 0,
522 redirection_entries: 24,
523 });
524
525 let descriptor = IrqDescriptor {
526 is_consumer: false,
527 trigger: InterruptTrigger::Level,
528 polarity: InterruptPolarity::ActiveLow,
529 is_shared: true,
530 is_wake_capable: false,
531 irq: 1 << 10,
532 };
533 let gsi = irq_descriptor_gsi(&descriptor).unwrap();
534
535 assert_eq!(gsi, 10);
536 let route = routing
537 .resolve_gsi(gsi)
538 .expect("IOAPIC routes the legacy GSI from the ACPI PCI link");
539 assert_eq!(route.gsi, 10);
540 assert_eq!(route.controller_input, 10);
541 }
542
543 #[test]
544 fn pci_link_descriptor_reports_selected_power_of_two_gsi_directly() {
545 let resource = LinkIrqResource {
546 kind: LinkIrqResourceKind::SmallIrq,
547 descriptor: IrqDescriptor {
548 is_consumer: false,
549 trigger: InterruptTrigger::Level,
550 polarity: InterruptPolarity::ActiveLow,
551 is_shared: true,
552 is_wake_capable: false,
553 irq: 1 << 4,
554 },
555 irqs: alloc::vec![4],
556 };
557
558 let descriptor = resource.descriptor_for_irq(4);
559 assert_eq!(descriptor.irq, 4);
560 assert_eq!(pci_irq_descriptor_gsi(&descriptor), Some(4));
561 }
562
563 #[test]
564 fn pch_pic_routes_map_acpi_gsi_to_controller_input() {
565 let mut routing = AcpiRouting::new();
566 routing.add_pch_pic(AcpiPchPic {
567 id: 1,
568 address: 0x1000_0000,
569 mmio_size: 0x1000,
570 gsi_count: 64,
571 gsi_base: 64,
572 });
573
574 let route = routing
575 .resolve_gsi(82)
576 .expect("GSI 82 should be covered by the PCH-PIC");
577 assert_eq!(route.controller, AcpiGsiController::PchPic);
578 assert_eq!(route.controller_id, 1);
579 assert_eq!(route.controller_address, 0x1000_0000);
580 assert_eq!(route.controller_input, 18);
581 assert_eq!(route.vector, 0x30 + 82);
582 assert!(routing.resolve_gsi(128).is_none());
583 }
584
585 #[test]
586 fn ioapic_routes_apply_isa_interrupt_source_overrides() {
587 let mut routing = AcpiRouting::new();
588 routing.add_io_apic(AcpiIoApic {
589 id: 0,
590 address: 0xfec0_0000,
591 gsi_base: 0,
592 redirection_entries: 24,
593 });
594 routing.add_isa_irq_override(AcpiIsaIrqOverride {
595 source: 0,
596 gsi: 2,
597 trigger: AcpiIrqTrigger::Level,
598 polarity: AcpiIrqPolarity::ActiveLow,
599 });
600
601 let route = routing
602 .resolve_gsi(2)
603 .expect("overridden ISA GSI should still route through the IOAPIC");
604 assert_eq!(route.vector, 0x32);
605 assert_eq!(route.controller_input, 2);
606 assert_eq!(route.trigger, AcpiIrqTrigger::Level);
607 assert_eq!(route.polarity, AcpiIrqPolarity::ActiveLow);
608 }
609
610 #[test]
611 fn pci_link_irq_selects_prs_when_crs_is_unassigned() {
612 let current = LinkIrqResource {
613 kind: LinkIrqResourceKind::ExtendedIrq,
614 descriptor: IrqDescriptor {
615 is_consumer: true,
616 trigger: InterruptTrigger::Level,
617 polarity: InterruptPolarity::ActiveHigh,
618 is_shared: true,
619 is_wake_capable: false,
620 irq: 0,
621 },
622 irqs: alloc::vec![0],
623 };
624 let possible = LinkIrqResource {
625 kind: LinkIrqResourceKind::ExtendedIrq,
626 descriptor: IrqDescriptor {
627 is_consumer: true,
628 trigger: InterruptTrigger::Level,
629 polarity: InterruptPolarity::ActiveHigh,
630 is_shared: true,
631 is_wake_capable: false,
632 irq: 5,
633 },
634 irqs: alloc::vec![5, 10, 11],
635 };
636
637 let link = "\\_SB.LNKA".parse().unwrap();
638 let allocator = PciLinkAllocator::default();
639 let selection = select_pci_link_irq(&link, Some(¤t), Some(&possible), &allocator)
640 .expect("possible IRQs should allocate a PCI link");
641
642 assert_eq!(selection.irq, 10);
643 assert!(selection.needs_programming);
644 assert_eq!(selection.resource.irqs, alloc::vec![5, 10, 11]);
645 }
646
647 #[test]
648 fn pci_link_irq_allocator_spreads_unassigned_links() {
649 let possible = LinkIrqResource {
650 kind: LinkIrqResourceKind::ExtendedIrq,
651 descriptor: IrqDescriptor {
652 is_consumer: true,
653 trigger: InterruptTrigger::Level,
654 polarity: InterruptPolarity::ActiveHigh,
655 is_shared: true,
656 is_wake_capable: false,
657 irq: 5,
658 },
659 irqs: alloc::vec![5, 10, 11],
660 };
661 let first = "\\_SB.LNKA".parse().unwrap();
662 let second = "\\_SB.LNKB".parse().unwrap();
663 let mut allocator = PciLinkAllocator::default();
664
665 let first_selection = select_pci_link_irq(&first, None, Some(&possible), &allocator)
666 .expect("first link should allocate");
667 assert_eq!(first_selection.irq, 10);
668 allocator.commit(&first, first_selection.irq);
669
670 let second_selection = select_pci_link_irq(&second, None, Some(&possible), &allocator)
671 .expect("second link should allocate");
672 assert_eq!(second_selection.irq, 11);
673 }
674
675 #[test]
676 fn pci_link_srs_gap_detection_is_narrow() {
677 let gap = acpi::aml::AmlError::ObjectNotOfExpectedType {
678 expected: acpi::aml::object::ObjectType::Integer,
679 got: acpi::aml::object::ObjectType::BufferField,
680 };
681 let other = acpi::aml::AmlError::ObjectNotOfExpectedType {
682 expected: acpi::aml::object::ObjectType::Buffer,
683 got: acpi::aml::object::ObjectType::BufferField,
684 };
685
686 assert!(is_buffer_field_to_field_unit_store_gap(&gap));
687 assert!(!is_buffer_field_to_field_unit_store_gap(&other));
688 }
689
690 #[test]
691 fn qemu_pci_link_names_map_to_pirq_fields() {
692 assert_eq!(
693 pci_link_irq_field_candidates(&"\\_SB.LNKB".parse().unwrap()),
694 ["\\_SB.PRQB", "\\_SB.PRQ1"]
695 );
696 assert_eq!(
697 pci_link_irq_field_candidates(&"\\_SB.LNKG".parse().unwrap()),
698 ["\\_SB.PRQG"]
699 );
700 assert!(pci_link_irq_field_candidates(&"\\_SB.LNKS".parse().unwrap()).is_empty());
701 }
702
703 #[test]
704 fn pci_irq_route_preserves_descriptor_trigger_and_polarity() {
705 let mut routing = AcpiRouting::new();
706 routing.add_io_apic(AcpiIoApic {
707 id: 0,
708 address: 0xfec0_0000,
709 gsi_base: 0,
710 redirection_entries: 24,
711 });
712 let route = routing.resolve_gsi(16).unwrap();
713 let descriptor = IrqDescriptor {
714 is_consumer: true,
715 trigger: InterruptTrigger::Edge,
716 polarity: InterruptPolarity::ActiveHigh,
717 is_shared: false,
718 is_wake_capable: false,
719 irq: 16,
720 };
721
722 let route = route_with_irq_descriptor_flags(route, &descriptor);
723
724 assert_eq!(route.trigger, AcpiIrqTrigger::Edge);
725 assert_eq!(route.polarity, AcpiIrqPolarity::ActiveHigh);
726 }
727}
728
729#[derive(Debug, Clone, Copy, PartialEq, Eq)]
730pub struct AcpiPciIrqRoute {
731 pub address: PciAddress,
732 pub interrupt_pin: u8,
733 pub intx_route: PciIntxRoute,
734 pub gsi: AcpiGsiRoute,
735}
736
737#[derive(Debug, Clone, Copy, PartialEq, Eq)]
738pub struct AcpiResourceRange {
739 pub base: u64,
740 pub size: u64,
741}
742
743#[derive(Debug, Clone, PartialEq, Eq)]
744pub struct AcpiResourceDevice {
745 pub path: String,
746 pub hid: Option<String>,
747 pub cids: Vec<String>,
748 pub memory_ranges: Vec<AcpiResourceRange>,
749 pub io_ranges: Vec<AcpiResourceRange>,
750 pub irq_routes: Vec<AcpiGsiRoute>,
751}
752
753#[derive(Debug, Clone)]
754struct AcpiDeviceInfo {
755 path: String,
756 hid: Option<String>,
757 cids: Vec<String>,
758 memory_ranges: Vec<AcpiResourceRange>,
759 io_ranges: Vec<AcpiResourceRange>,
760 irq_routes: Vec<AcpiGsiRoute>,
761}
762
763#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
764pub enum AcpiResourceAddressSpace {
765 Memory,
766 Io,
767}
768
769#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
770pub struct AcpiResourceAddress {
771 pub space: AcpiResourceAddressSpace,
772 pub base: u64,
773}
774
775impl AcpiResourceAddress {
776 pub const fn memory(base: u64) -> Self {
777 Self {
778 space: AcpiResourceAddressSpace::Memory,
779 base,
780 }
781 }
782
783 pub const fn io(base: u64) -> Self {
784 Self {
785 space: AcpiResourceAddressSpace::Io,
786 base,
787 }
788 }
789
790 pub fn from_generic_address(address: GenericAddress) -> Option<Self> {
791 match address.address_space {
792 AddressSpace::SystemMemory => Some(Self::memory(address.address)),
793 AddressSpace::SystemIo => Some(Self::io(address.address)),
794 _ => None,
795 }
796 }
797}
798
799pub struct AcpiInfo<'a> {
800 pub root: &'a System,
801 pub path: &'a str,
802 pub irq_route: Option<AcpiGsiRoute>,
803 device: Option<&'a AcpiDeviceInfo>,
804}
805
806impl AcpiInfo<'_> {
807 pub const fn irq_route(&self) -> Option<AcpiGsiRoute> {
808 self.irq_route
809 }
810
811 pub fn hid(&self) -> Option<&str> {
812 self.device
813 .as_ref()
814 .and_then(|device| device.hid.as_deref())
815 }
816
817 pub fn cids(&self) -> &[String] {
818 self.device
819 .as_ref()
820 .map(|device| device.cids.as_slice())
821 .unwrap_or_default()
822 }
823
824 pub fn memory_ranges(&self) -> &[AcpiResourceRange] {
825 self.device
826 .as_ref()
827 .map(|device| device.memory_ranges.as_slice())
828 .unwrap_or_default()
829 }
830
831 pub fn io_ranges(&self) -> &[AcpiResourceRange] {
832 self.device
833 .as_ref()
834 .map(|device| device.io_ranges.as_slice())
835 .unwrap_or_default()
836 }
837
838 pub fn irq_routes(&self) -> &[AcpiGsiRoute] {
839 self.device
840 .as_ref()
841 .map(|device| device.irq_routes.as_slice())
842 .unwrap_or_default()
843 }
844}
845
846impl From<AcpiDeviceInfo> for AcpiResourceDevice {
847 fn from(value: AcpiDeviceInfo) -> Self {
848 Self {
849 path: value.path,
850 hid: value.hid,
851 cids: value.cids,
852 memory_ranges: value.memory_ranges,
853 io_ranges: value.io_ranges,
854 irq_routes: value.irq_routes,
855 }
856 }
857}
858
859pub struct ProbeAcpi<'a> {
860 info: AcpiInfo<'a>,
861 platform: PlatformDevice,
862}
863
864impl<'a> ProbeAcpi<'a> {
865 #[allow(dead_code)]
866 pub(crate) fn new(info: AcpiInfo<'a>, platform: PlatformDevice) -> Self {
867 Self { info, platform }
868 }
869
870 pub const fn info(&self) -> &AcpiInfo<'a> {
871 &self.info
872 }
873
874 pub fn into_platform_device(self) -> PlatformDevice {
875 self.platform
876 }
877
878 pub fn into_parts(self) -> (AcpiInfo<'a>, PlatformDevice) {
879 (self.info, self.platform)
880 }
881}
882
883pub type FnOnProbe = for<'a> fn(ProbeAcpi<'a>) -> Result<(), OnProbeError>;
884
885pub fn check_root(root: AcpiRoot) -> Result<(), DriverError> {
886 if root.rsdp == 0 {
887 return Err(acpi_error(AcpiError::NoValidRsdp));
888 }
889 root.tables().map(|_| ()).map_err(acpi_error)
890}
891
892pub fn init(root: AcpiRoot) -> Result<(), DriverError> {
893 let system = System::new(root)?;
894 info!(
895 "ACPI initialized: {} PCI ECAM region(s), {} IOAPIC(s), {} PCH-PIC(s)",
896 system.pci_ecam_regions().len(),
897 system.routing().io_apics().len(),
898 system.routing().pch_pics().len()
899 );
900 SYSTEM.call_once(|| system);
901 Ok(())
902}
903
904pub(crate) fn try_probe_register(
905 register: &DriverRegister,
906) -> Option<Result<alloc::vec::Vec<Result<(), OnProbeError>>, ProbeError>> {
907 SYSTEM.get().map(|system| system.probe_register(register))
908}
909
910pub(crate) fn try_system() -> Option<&'static System> {
911 SYSTEM.get()
912}
913
914pub fn with_acpi<T>(f: impl FnOnce(&System) -> T) -> Option<T> {
915 try_system().map(f)
916}
917
918pub fn spcr_console_device_id() -> Option<DeviceId> {
919 try_system().and_then(System::spcr_console_device_id)
920}
921
922fn acpi_error(err: AcpiError) -> DriverError {
923 DriverError::Unknown(format!("{err:?}"))
924}
925
926fn on_probe_error(err: impl core::fmt::Debug) -> OnProbeError {
927 OnProbeError::other(format!("{err:?}"))
928}
929
930fn identity_phys_to_virt(paddr: usize) -> *mut u8 {
931 paddr as *mut u8
932}
933
934#[derive(Clone)]
935struct AcpiHandler {
936 root: AcpiRoot,
937 pci_ecam_regions: Rc<Vec<AcpiPciEcam>>,
938}
939
940impl AcpiHandler {
941 fn new(root: AcpiRoot, pci_ecam_regions: Vec<AcpiPciEcam>) -> Self {
942 Self {
943 root,
944 pci_ecam_regions: Rc::new(pci_ecam_regions),
945 }
946 }
947
948 fn virt_addr(&self, physical_address: usize) -> usize {
949 (self.root.phys_to_virt)(physical_address) as usize
950 }
951
952 fn pci_config_ptr(
953 &self,
954 address: acpi::PciAddress,
955 offset: u16,
956 width: usize,
957 ) -> Option<*mut u8> {
958 let offset = usize::from(offset);
959 if offset.checked_add(width)? > 4096 {
960 return None;
961 }
962
963 let bus = address.bus();
964 let region = self.pci_ecam_regions.iter().find(|region| {
965 address.segment() == region.segment_group
966 && bus >= region.bus_start
967 && bus <= region.bus_end
968 })?;
969 let bus_offset = usize::from(bus - region.bus_start) << 20;
970 let device_offset = usize::from(address.device()) << 15;
971 let function_offset = usize::from(address.function()) << 12;
972 let physical_address =
973 region.base_address as usize + bus_offset + device_offset + function_offset + offset;
974
975 Some((self.root.phys_to_virt)(physical_address))
976 }
977}
978
979impl Handler for AcpiHandler {
980 unsafe fn map_physical_region<T>(
981 &self,
982 physical_address: usize,
983 size: usize,
984 ) -> PhysicalMapping<Self, T> {
985 PhysicalMapping {
986 physical_start: physical_address,
987 virtual_start: NonNull::new(self.virt_addr(physical_address) as *mut T)
988 .expect("ACPI physical mapping must not be null"),
989 region_length: size,
990 mapped_length: size,
991 handler: self.clone(),
992 }
993 }
994
995 fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
996
997 fn read_u8(&self, address: usize) -> u8 {
998 unsafe { (self.virt_addr(address) as *const u8).read_volatile() }
999 }
1000
1001 fn read_u16(&self, address: usize) -> u16 {
1002 unsafe { (self.virt_addr(address) as *const u16).read_volatile() }
1003 }
1004
1005 fn read_u32(&self, address: usize) -> u32 {
1006 unsafe { (self.virt_addr(address) as *const u32).read_volatile() }
1007 }
1008
1009 fn read_u64(&self, address: usize) -> u64 {
1010 unsafe { (self.virt_addr(address) as *const u64).read_volatile() }
1011 }
1012
1013 fn write_u8(&self, address: usize, value: u8) {
1014 unsafe { (self.virt_addr(address) as *mut u8).write_volatile(value) }
1015 }
1016
1017 fn write_u16(&self, address: usize, value: u16) {
1018 unsafe { (self.virt_addr(address) as *mut u16).write_volatile(value) }
1019 }
1020
1021 fn write_u32(&self, address: usize, value: u32) {
1022 unsafe { (self.virt_addr(address) as *mut u32).write_volatile(value) }
1023 }
1024
1025 fn write_u64(&self, address: usize, value: u64) {
1026 unsafe { (self.virt_addr(address) as *mut u64).write_volatile(value) }
1027 }
1028
1029 fn read_io_u8(&self, port: u16) -> u8 {
1030 read_io_u8(port)
1031 }
1032
1033 fn read_io_u16(&self, port: u16) -> u16 {
1034 read_io_u16(port)
1035 }
1036
1037 fn read_io_u32(&self, port: u16) -> u32 {
1038 read_io_u32(port)
1039 }
1040
1041 fn write_io_u8(&self, port: u16, value: u8) {
1042 write_io_u8(port, value);
1043 }
1044
1045 fn write_io_u16(&self, port: u16, value: u16) {
1046 write_io_u16(port, value);
1047 }
1048
1049 fn write_io_u32(&self, port: u16, value: u32) {
1050 write_io_u32(port, value);
1051 }
1052
1053 fn read_pci_u8(&self, address: acpi::PciAddress, offset: u16) -> u8 {
1054 if let Some(ptr) = self.pci_config_ptr(address, offset, 1) {
1055 return unsafe { ptr.read_volatile() };
1056 }
1057 pci_legacy_read_u8(address, offset).unwrap_or(u8::MAX)
1058 }
1059
1060 fn read_pci_u16(&self, address: acpi::PciAddress, offset: u16) -> u16 {
1061 let lo = u16::from(self.read_pci_u8(address, offset));
1062 let hi = u16::from(self.read_pci_u8(address, offset.saturating_add(1)));
1063 lo | (hi << 8)
1064 }
1065
1066 fn read_pci_u32(&self, address: acpi::PciAddress, offset: u16) -> u32 {
1067 let b0 = u32::from(self.read_pci_u8(address, offset));
1068 let b1 = u32::from(self.read_pci_u8(address, offset.saturating_add(1)));
1069 let b2 = u32::from(self.read_pci_u8(address, offset.saturating_add(2)));
1070 let b3 = u32::from(self.read_pci_u8(address, offset.saturating_add(3)));
1071 b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
1072 }
1073
1074 fn write_pci_u8(&self, address: acpi::PciAddress, offset: u16, value: u8) {
1075 if let Some(ptr) = self.pci_config_ptr(address, offset, 1) {
1076 unsafe { ptr.write_volatile(value) };
1077 return;
1078 }
1079 pci_legacy_write_u8(address, offset, value);
1080 }
1081
1082 fn write_pci_u16(&self, address: acpi::PciAddress, offset: u16, value: u16) {
1083 self.write_pci_u8(address, offset, value as u8);
1084 self.write_pci_u8(address, offset.saturating_add(1), (value >> 8) as u8);
1085 }
1086
1087 fn write_pci_u32(&self, address: acpi::PciAddress, offset: u16, value: u32) {
1088 self.write_pci_u8(address, offset, value as u8);
1089 self.write_pci_u8(address, offset.saturating_add(1), (value >> 8) as u8);
1090 self.write_pci_u8(address, offset.saturating_add(2), (value >> 16) as u8);
1091 self.write_pci_u8(address, offset.saturating_add(3), (value >> 24) as u8);
1092 }
1093
1094 fn nanos_since_boot(&self) -> u64 {
1095 0
1096 }
1097
1098 fn stall(&self, microseconds: u64) {
1099 for _ in 0..microseconds.saturating_mul(100) {
1100 core::hint::spin_loop();
1101 }
1102 }
1103
1104 fn sleep(&self, milliseconds: u64) {
1105 self.stall(milliseconds.saturating_mul(1000));
1106 }
1107
1108 fn create_mutex(&self) -> acpi::Handle {
1109 acpi::Handle(0)
1110 }
1111
1112 fn acquire(&self, _mutex: acpi::Handle, _timeout: u16) -> Result<(), acpi::aml::AmlError> {
1113 let _guard = NULL_LOCK.lock();
1114 Ok(())
1115 }
1116
1117 fn release(&self, _mutex: acpi::Handle) {}
1118}
1119
1120impl AcpiRoot {
1121 fn handler(self) -> AcpiHandler {
1122 AcpiHandler::new(self, Vec::new())
1123 }
1124
1125 fn handler_with_pci_ecam(self, pci_ecam_regions: Vec<AcpiPciEcam>) -> AcpiHandler {
1126 AcpiHandler::new(self, pci_ecam_regions)
1127 }
1128
1129 fn tables(self) -> Result<AcpiTables<AcpiHandler>, AcpiError> {
1130 unsafe { AcpiTables::from_rsdp(self.handler(), self.rsdp) }
1131 }
1132}
1133
1134pub struct System {
1135 ecam_regions: Vec<AcpiPciEcam>,
1136 routing: AcpiRouting,
1137 interpreter: Interpreter<AcpiHandler>,
1138 handler: AcpiHandler,
1139 pci: Option<AcpiPciNamespace>,
1140 probed_names: Mutex<BTreeSet<&'static str>>,
1141 populated_paths: Mutex<BTreeMap<String, DeviceId>>,
1142 populated_resources: Mutex<BTreeMap<AcpiResourceAddress, DeviceId>>,
1143}
1144
1145unsafe impl Send for System {}
1146unsafe impl Sync for System {}
1147
1148struct AcpiPciNamespace {
1149 link_allocator: Mutex<PciLinkAllocator>,
1150 roots: Vec<AcpiPciRoot>,
1151}
1152
1153struct AcpiPciRoot {
1154 segment: u16,
1155 bus: u8,
1156 path: String,
1157 prt: Option<PciRoutingTable>,
1158 link_prt: Option<PciLinkRoutingTable>,
1159}
1160
1161impl System {
1162 pub fn new(root: AcpiRoot) -> Result<Self, DriverError> {
1163 let handler = root.handler();
1164 let tables =
1165 unsafe { AcpiTables::from_rsdp(handler.clone(), root.rsdp) }.map_err(acpi_error)?;
1166 let ecam_regions = read_pci_ecam_regions(&tables)?;
1167 let routing = read_interrupt_routing(&tables)?;
1168 let namespace_handler = root.handler_with_pci_ecam(ecam_regions.clone());
1169 let platform = AcpiPlatform::new(tables, namespace_handler.clone()).map_err(acpi_error)?;
1170 let interpreter = Interpreter::new_from_platform(&platform).map_err(acpi_error)?;
1171 interpreter.initialize_namespace();
1172 let pci = match read_pci_namespace(&interpreter) {
1173 Ok(pci) => Some(pci),
1174 Err(err) => {
1175 warn!("failed to discover ACPI PCI namespace: {err:?}");
1176 None
1177 }
1178 };
1179
1180 Ok(Self {
1181 ecam_regions,
1182 routing,
1183 interpreter,
1184 handler: namespace_handler,
1185 pci,
1186 probed_names: Mutex::new(BTreeSet::new()),
1187 populated_paths: Mutex::new(BTreeMap::new()),
1188 populated_resources: Mutex::new(BTreeMap::new()),
1189 })
1190 }
1191
1192 pub fn pci_ecam_regions(&self) -> &[AcpiPciEcam] {
1193 &self.ecam_regions
1194 }
1195
1196 pub fn routing(&self) -> &AcpiRouting {
1197 &self.routing
1198 }
1199
1200 pub fn path_to_device_id(&self, path: &str) -> Option<DeviceId> {
1201 self.populated_paths.lock().get(path).copied()
1202 }
1203
1204 pub fn resource_address_to_device_id(&self, address: AcpiResourceAddress) -> Option<DeviceId> {
1205 self.populated_resources.lock().get(&address).copied()
1206 }
1207
1208 pub fn spcr_console_device_id(&self) -> Option<DeviceId> {
1209 let tables = unsafe { AcpiTables::from_rsdp(self.handler.clone(), self.handler.root.rsdp) }
1210 .map_err(acpi_error)
1211 .ok()?;
1212 tables
1213 .find_tables::<Spcr>()
1214 .filter(|spcr| is_supported_spcr_interface(spcr.interface_type()))
1215 .find_map(|spcr| {
1216 spcr_namespace_device_id(self, &spcr)
1217 .or_else(|| spcr_resource_device_id(self, &spcr))
1218 })
1219 }
1220
1221 pub fn resource_devices(&self) -> Result<Vec<AcpiResourceDevice>, ProbeError> {
1222 self.device_infos().map(|devices| {
1223 devices
1224 .into_iter()
1225 .map(AcpiResourceDevice::from)
1226 .collect::<Vec<_>>()
1227 })
1228 }
1229
1230 pub fn serial_console_memory_range(&self) -> Option<AcpiResourceRange> {
1231 let tables = self.handler.root.tables().ok()?;
1232 let spcr = tables.find_table::<acpi::sdt::spcr::Spcr>()?;
1233 let address = spcr.base_address()?.ok()?;
1234 if address.address_space != acpi::address::AddressSpace::SystemMemory {
1235 return None;
1236 }
1237
1238 Some(AcpiResourceRange {
1239 base: address.address,
1240 size: spcr_uart_register_size(address.access_size),
1241 })
1242 }
1243
1244 pub fn pci_irq_for_endpoint(
1245 &self,
1246 info: PciInfo,
1247 ) -> Result<Option<AcpiPciIrqRoute>, OnProbeError> {
1248 let Some(intx_route) = info.intx_route else {
1249 return Ok(None);
1250 };
1251 let Some(irq) = self.resolve_endpoint_gsi(info.address, intx_route)? else {
1252 return Ok(None);
1253 };
1254 let Some(gsi) = pci_irq_descriptor_gsi(&irq) else {
1255 return Err(OnProbeError::other(format!(
1256 "ACPI PCI endpoint {} pin {} returned an invalid IRQ descriptor: {:?}",
1257 info.address, intx_route.root_pin, irq
1258 )));
1259 };
1260 if gsi == 0 {
1261 return Ok(None);
1262 }
1263
1264 let Some(route) = self.routing.resolve_gsi(gsi) else {
1265 return Err(OnProbeError::other(format!(
1266 "ACPI GSI {} for PCI endpoint {} is not covered by a registered GSI controller",
1267 gsi, info.address
1268 )));
1269 };
1270 let route = route_with_irq_descriptor_flags(route, &irq);
1271
1272 Ok(Some(AcpiPciIrqRoute {
1273 address: info.address,
1274 interrupt_pin: intx_route.root_pin,
1275 intx_route,
1276 gsi: route,
1277 }))
1278 }
1279
1280 fn resolve_endpoint_gsi(
1281 &self,
1282 address: PciAddress,
1283 route: PciIntxRoute,
1284 ) -> Result<Option<IrqDescriptor>, OnProbeError> {
1285 let pin = acpi_pin(route.root_pin)?;
1286 let Some(pci) = &self.pci else {
1287 return Ok(None);
1288 };
1289 let roots = self.pci_root_candidates(address, pci);
1290 if roots.is_empty() {
1291 return Ok(None);
1292 }
1293
1294 for root in roots {
1295 let Some(prt) = &root.prt else {
1296 continue;
1297 };
1298
1299 if let Some(link_prt) = &root.link_prt
1300 && let Some(route) = link_prt
1301 .route(
1302 u16::from(route.root_device),
1303 u16::from(route.root_function),
1304 pin,
1305 &self.interpreter,
1306 &self.handler,
1307 &mut pci.link_allocator.lock(),
1308 )
1309 .map_err(on_probe_error)?
1310 {
1311 return Ok(Some(route));
1312 }
1313
1314 match prt.route(
1315 u16::from(route.root_device),
1316 u16::from(route.root_function),
1317 pin,
1318 &self.interpreter,
1319 ) {
1320 Ok(route) => return Ok(Some(route)),
1321 Err(AmlError::PrtNoEntry) => {}
1322 Err(err) => return Err(on_probe_error(err)),
1323 }
1324 }
1325
1326 Ok(None)
1327 }
1328
1329 fn pci_root_candidates<'a>(
1330 &self,
1331 address: PciAddress,
1332 pci: &'a AcpiPciNamespace,
1333 ) -> Vec<&'a AcpiPciRoot> {
1334 let mut roots = Vec::new();
1335 if let Some(root) = pci
1336 .roots
1337 .iter()
1338 .find(|root| root.segment == address.segment() && root.bus == address.bus())
1339 .or_else(|| {
1340 pci.roots
1341 .iter()
1342 .find(|root| root.segment == address.segment() && root.bus == 0)
1343 })
1344 {
1345 roots.push(root);
1346 }
1347 for path in PCI_ROOT_FALLBACK_PATHS {
1348 if let Some(root) = pci.roots.iter().find(|root| root.path == *path)
1349 && !roots.iter().any(|candidate| candidate.path == root.path)
1350 {
1351 roots.push(root);
1352 }
1353 }
1354 roots
1355 }
1356
1357 fn device_infos_for_ids(&self, ids: &[AcpiId]) -> Result<Vec<AcpiDeviceInfo>, ProbeError> {
1358 let mut devices = Vec::new();
1359 let mut namespace = self.interpreter.namespace.lock().clone();
1360 namespace
1361 .traverse(|path, level| {
1362 if level.kind != NamespaceLevelKind::Device {
1363 return Ok(true);
1364 }
1365 let Some((hid, cids)) = acpi_device_ids(&self.interpreter, path)? else {
1366 return Ok(true);
1367 };
1368 if !acpi_ids_match(&hid, &cids, ids) {
1369 return Ok(true);
1370 }
1371 let resources = read_device_resources(&self.interpreter, path, &self.routing)?;
1372 devices.push(AcpiDeviceInfo {
1373 path: path.as_string(),
1374 hid: Some(hid),
1375 cids,
1376 memory_ranges: resources.memory_ranges,
1377 io_ranges: resources.io_ranges,
1378 irq_routes: resources.irq_routes,
1379 });
1380 Ok(true)
1381 })
1382 .map_err(|err| ProbeError::OnProbe(OnProbeError::other(format!("{err:?}"))))?;
1383 Ok(devices)
1384 }
1385
1386 fn device_infos(&self) -> Result<Vec<AcpiDeviceInfo>, ProbeError> {
1387 let mut devices = Vec::new();
1388 let mut namespace = self.interpreter.namespace.lock().clone();
1389 namespace
1390 .traverse(|path, level| {
1391 if level.kind != NamespaceLevelKind::Device {
1392 return Ok(true);
1393 }
1394 let Some((hid, cids)) = acpi_device_ids(&self.interpreter, path)? else {
1395 return Ok(true);
1396 };
1397 let resources = read_device_resources(&self.interpreter, path, &self.routing)?;
1398 devices.push(AcpiDeviceInfo {
1399 path: path.as_string(),
1400 hid: Some(hid),
1401 cids,
1402 memory_ranges: resources.memory_ranges,
1403 io_ranges: resources.io_ranges,
1404 irq_routes: resources.irq_routes,
1405 });
1406 Ok(true)
1407 })
1408 .map_err(|err| ProbeError::OnProbe(OnProbeError::other(format!("{err:?}"))))?;
1409 Ok(devices)
1410 }
1411
1412 fn probe_register(
1413 &self,
1414 register: &DriverRegister,
1415 ) -> Result<Vec<Result<(), OnProbeError>>, ProbeError> {
1416 let mut out = Vec::new();
1417 for probe in register.probe_kinds {
1418 let ProbeKind::Acpi { ids, on_probe } = probe else {
1419 continue;
1420 };
1421 if self.probed_names.lock().contains(register.name) {
1422 continue;
1423 }
1424
1425 if !ids.is_empty() && !is_root_acpi_id_list(ids) {
1426 for device in self.device_infos_for_ids(ids)? {
1427 if self.probed_names.lock().contains(register.name) {
1428 continue;
1429 }
1430 let desc = crate::Descriptor {
1431 name: register.name,
1432 device_id: DeviceId::new(),
1433 irq_parent: None,
1434 };
1435 let device_id = desc.device_id();
1436 let info = AcpiInfo {
1437 root: self,
1438 path: &device.path,
1439 irq_route: device.irq_routes.first().copied(),
1440 device: Some(&device),
1441 };
1442 let res = on_probe(ProbeAcpi::new(info, PlatformDevice::new(desc)));
1443 if res.is_ok() {
1444 self.probed_names.lock().insert(register.name);
1445 self.note_populated_device(device_id, &device);
1446 }
1447 out.push(res);
1448 }
1449 continue;
1450 }
1451
1452 let desc = crate::Descriptor {
1453 name: register.name,
1454 device_id: DeviceId::new(),
1455 irq_parent: None,
1456 };
1457 let info = AcpiInfo {
1458 root: self,
1459 path: "\\",
1460 irq_route: None,
1461 device: None,
1462 };
1463 let res = on_probe(ProbeAcpi::new(info, PlatformDevice::new(desc)));
1464 if res.is_ok() {
1465 self.probed_names.lock().insert(register.name);
1466 }
1467 out.push(res);
1468 }
1469 Ok(out)
1470 }
1471
1472 fn note_populated_device(&self, device_id: DeviceId, device: &AcpiDeviceInfo) {
1473 self.populated_paths
1474 .lock()
1475 .insert(device.path.clone(), device_id);
1476
1477 let mut resources = self.populated_resources.lock();
1478 for range in &device.memory_ranges {
1479 resources.insert(AcpiResourceAddress::memory(range.base), device_id);
1480 }
1481 for range in &device.io_ranges {
1482 resources.insert(AcpiResourceAddress::io(range.base), device_id);
1483 }
1484 }
1485}
1486
1487fn is_supported_spcr_interface(interface: SpcrInterfaceType) -> bool {
1488 matches!(
1489 interface,
1490 SpcrInterfaceType::Full16550
1491 | SpcrInterfaceType::Full16450
1492 | SpcrInterfaceType::Generic16550
1493 | SpcrInterfaceType::ArmPL011
1494 | SpcrInterfaceType::ArmSBSAGeneric32bit
1495 | SpcrInterfaceType::ArmSBSAGeneric
1496 )
1497}
1498
1499fn spcr_namespace_device_id(system: &System, spcr: &Spcr) -> Option<DeviceId> {
1500 let namespace = spcr.namespace_string().ok()?.trim_end_matches('\0');
1501 if namespace.is_empty() || namespace == "." {
1502 return None;
1503 }
1504 system.path_to_device_id(namespace)
1505}
1506
1507fn spcr_resource_device_id(system: &System, spcr: &Spcr) -> Option<DeviceId> {
1508 let address = spcr.base_address()?.ok()?;
1509 let address = AcpiResourceAddress::from_generic_address(address)?;
1510 system.resource_address_to_device_id(address)
1511}
1512
1513fn read_pci_ecam_regions(
1514 tables: &AcpiTables<AcpiHandler>,
1515) -> Result<Vec<AcpiPciEcam>, DriverError> {
1516 let regions = PciConfigRegions::new(tables).map_err(acpi_error)?;
1517 Ok(regions
1518 .regions
1519 .iter()
1520 .map(|region| AcpiPciEcam {
1521 segment_group: region.pci_segment_group,
1522 bus_start: region.bus_number_start,
1523 bus_end: region.bus_number_end,
1524 base_address: region.base_address,
1525 })
1526 .collect())
1527}
1528
1529fn read_interrupt_routing(tables: &AcpiTables<AcpiHandler>) -> Result<AcpiRouting, DriverError> {
1530 let (model, _) = InterruptModel::new(tables).map_err(acpi_error)?;
1531 let mut routing = AcpiRouting::new();
1532 if let InterruptModel::Apic(apic) = model {
1533 for io_apic in &apic.io_apics {
1534 routing.add_io_apic(AcpiIoApic {
1535 id: io_apic.id,
1536 address: io_apic.address,
1537 gsi_base: io_apic.global_system_interrupt_base,
1538 redirection_entries: 24,
1539 });
1540 }
1541 for irq_override in &apic.interrupt_source_overrides {
1542 routing.add_isa_irq_override(AcpiIsaIrqOverride {
1543 source: irq_override.isa_source,
1544 gsi: irq_override.global_system_interrupt,
1545 trigger: match irq_override.trigger_mode {
1546 TriggerMode::Edge => AcpiIrqTrigger::Edge,
1547 TriggerMode::Level => AcpiIrqTrigger::Level,
1548 _ => AcpiIrqTrigger::Edge,
1549 },
1550 polarity: match irq_override.polarity {
1551 Polarity::ActiveHigh => AcpiIrqPolarity::ActiveHigh,
1552 Polarity::ActiveLow => AcpiIrqPolarity::ActiveLow,
1553 _ => AcpiIrqPolarity::ActiveHigh,
1554 },
1555 });
1556 }
1557 }
1558 read_loongarch_pch_pic_routing(tables, &mut routing);
1559 Ok(routing)
1560}
1561
1562#[repr(C, packed)]
1563#[derive(Clone, Copy)]
1564struct RawMadtEntryHeader {
1565 entry_type: u8,
1566 length: u8,
1567}
1568
1569#[repr(C, packed)]
1570#[derive(Clone, Copy)]
1571struct RawMadtBioPic {
1572 header: RawMadtEntryHeader,
1573 version: u8,
1574 address: u64,
1575 size: u16,
1576 id: u16,
1577 gsi_base: u16,
1578}
1579
1580const ACPI_MADT_TYPE_BIO_PIC: u8 = 22;
1581const RAW_MADT_HEADER_LEN: usize = core::mem::size_of::<acpi::sdt::SdtHeader>() + 8;
1582
1583fn read_loongarch_pch_pic_routing(tables: &AcpiTables<AcpiHandler>, routing: &mut AcpiRouting) {
1584 let Some(madt) = tables.find_table::<acpi::sdt::madt::Madt>() else {
1585 return;
1586 };
1587
1588 let base = madt.virtual_start.as_ptr() as *const u8;
1589 let length = madt.region_length;
1590 if length < RAW_MADT_HEADER_LEN {
1591 return;
1592 }
1593
1594 let mut offset = RAW_MADT_HEADER_LEN;
1595 while offset + core::mem::size_of::<RawMadtEntryHeader>() <= length {
1596 let header = unsafe { (base.add(offset) as *const RawMadtEntryHeader).read_unaligned() };
1597 let entry_len = usize::from(header.length);
1598 if entry_len < core::mem::size_of::<RawMadtEntryHeader>() || offset + entry_len > length {
1599 break;
1600 }
1601
1602 if header.entry_type == ACPI_MADT_TYPE_BIO_PIC {
1603 read_loongarch_bio_pic_entry(base, offset, entry_len, routing);
1604 }
1605
1606 offset += entry_len;
1607 }
1608}
1609
1610fn read_loongarch_bio_pic_entry(
1611 base: *const u8,
1612 offset: usize,
1613 entry_len: usize,
1614 routing: &mut AcpiRouting,
1615) {
1616 if entry_len < core::mem::size_of::<RawMadtBioPic>() {
1617 warn!("ignore short LoongArch BIO_PIC MADT entry: {entry_len} bytes");
1618 return;
1619 }
1620
1621 let entry = unsafe { (base.add(offset) as *const RawMadtBioPic).read_unaligned() };
1622
1623 routing.add_pch_pic(AcpiPchPic {
1624 id: entry.id,
1625 address: entry.address,
1626 mmio_size: entry.size,
1627 gsi_count: LOONGARCH_PCH_PIC_GSI_COUNT,
1628 gsi_base: u32::from(entry.gsi_base),
1629 });
1630}
1631
1632fn spcr_uart_register_size(access_size: u8) -> u64 {
1633 let access_bytes = match access_size {
1634 1 => 1,
1635 2 => 2,
1636 3 => 4,
1637 4 => 8,
1638 _ => 1,
1639 };
1640 access_bytes * 8
1641}
1642
1643#[derive(Default)]
1644struct AcpiDeviceResources {
1645 memory_ranges: Vec<AcpiResourceRange>,
1646 io_ranges: Vec<AcpiResourceRange>,
1647 irq_routes: Vec<AcpiGsiRoute>,
1648}
1649
1650fn is_root_acpi_id_list(ids: &[AcpiId]) -> bool {
1651 ids.iter().any(|id| id.hid == "ACPIIOAP")
1652}
1653
1654fn acpi_ids_match(hid: &str, cids: &[String], ids: &[AcpiId]) -> bool {
1655 ids.iter().any(|id| {
1656 id.hid == hid
1657 || id.cids.contains(&hid)
1658 || cids
1659 .iter()
1660 .any(|cid| id.hid == cid || id.cids.contains(&cid.as_str()))
1661 })
1662}
1663
1664fn acpi_device_ids(
1665 interpreter: &Interpreter<AcpiHandler>,
1666 path: &AmlName,
1667) -> Result<Option<(String, Vec<String>)>, AmlError> {
1668 let Some(hid_object) = eval_child(interpreter, path, "_HID")? else {
1669 return Ok(None);
1670 };
1671 let Some(hid) = acpi_id_from_object(&hid_object) else {
1672 return Ok(None);
1673 };
1674 let cids = match eval_child(interpreter, path, "_CID")? {
1675 Some(value) => acpi_ids_from_object(&value),
1676 None => Vec::new(),
1677 };
1678 Ok(Some((hid, cids)))
1679}
1680
1681fn acpi_id_from_object(value: &Object) -> Option<String> {
1682 match value {
1683 Object::String(id) => Some(id.clone()),
1684 Object::Integer(id) => decode_eisa_id(*id as u32),
1685 _ => None,
1686 }
1687}
1688
1689fn acpi_ids_from_object(value: &Object) -> Vec<String> {
1690 match value {
1691 Object::Package(values) => values
1692 .iter()
1693 .filter_map(|value| acpi_id_from_object(value))
1694 .collect(),
1695 _ => acpi_id_from_object(value).into_iter().collect(),
1696 }
1697}
1698
1699fn read_device_resources(
1700 interpreter: &Interpreter<AcpiHandler>,
1701 path: &AmlName,
1702 routing: &AcpiRouting,
1703) -> Result<AcpiDeviceResources, AmlError> {
1704 let Some(value) = eval_wrapped_child(interpreter, path, "_CRS")? else {
1705 return Ok(AcpiDeviceResources::default());
1706 };
1707 let resources = resource_descriptor_list(value)?;
1708 let mut out = AcpiDeviceResources::default();
1709 for resource in resources {
1710 match resource {
1711 Resource::MemoryRange(memory) => match memory {
1712 acpi::aml::resource::MemoryRangeDescriptor::FixedLocation {
1713 base_address,
1714 range_length,
1715 ..
1716 } => out.memory_ranges.push(AcpiResourceRange {
1717 base: u64::from(base_address),
1718 size: u64::from(range_length),
1719 }),
1720 },
1721 Resource::AddressSpace(address) => {
1722 let range = AcpiResourceRange {
1723 base: address.address_range.0,
1724 size: address.length,
1725 };
1726 match address.resource_type {
1727 AddressSpaceResourceType::MemoryRange => out.memory_ranges.push(range),
1728 AddressSpaceResourceType::IORange => out.io_ranges.push(range),
1729 AddressSpaceResourceType::BusNumberRange => {}
1730 }
1731 }
1732 Resource::IOPort(io) => out.io_ranges.push(AcpiResourceRange {
1733 base: u64::from(io.memory_range.0),
1734 size: u64::from(io.range_length),
1735 }),
1736 Resource::Irq(irq) => {
1737 if let Some(gsi) = irq_descriptor_gsi(&irq)
1738 && let Some(route) = routing.resolve_gsi(gsi)
1739 {
1740 out.irq_routes
1741 .push(route_with_irq_descriptor_flags(route, &irq));
1742 }
1743 }
1744 Resource::Dma(_) => {}
1745 }
1746 }
1747 Ok(out)
1748}
1749
1750fn read_pci_namespace(
1751 interpreter: &Interpreter<AcpiHandler>,
1752) -> Result<AcpiPciNamespace, AcpiError> {
1753 let mut roots = Vec::new();
1754 {
1755 let mut namespace = interpreter.namespace.lock().clone();
1756 namespace
1757 .traverse(|path, level| {
1758 if level.kind == NamespaceLevelKind::Device && is_pci_root(interpreter, path) {
1759 let segment =
1760 eval_integer_child(interpreter, path, "_SEG")?.unwrap_or(0) as u16;
1761 let bus = eval_integer_child(interpreter, path, "_BBN")?.unwrap_or(0) as u8;
1762 roots.push(AcpiPciRoot {
1763 segment,
1764 bus,
1765 path: path.as_string(),
1766 prt: None,
1767 link_prt: None,
1768 });
1769 }
1770 Ok(true)
1771 })
1772 .map_err(AcpiError::Aml)?;
1773 }
1774
1775 for root in &mut roots {
1776 root.prt = read_pci_routing_table(interpreter, &root.path)?;
1777 root.link_prt = read_pci_link_routing_table(interpreter, &root.path)?;
1778 }
1779 for path in PCI_ROOT_FALLBACK_PATHS {
1780 if roots.iter().any(|root| root.path == *path) {
1781 continue;
1782 }
1783 let Some(prt) = read_pci_routing_table(interpreter, path)? else {
1784 continue;
1785 };
1786 let link_prt = read_pci_link_routing_table(interpreter, path)?;
1787 roots.push(AcpiPciRoot {
1788 segment: 0,
1789 bus: 0,
1790 path: path.to_string(),
1791 prt: Some(prt),
1792 link_prt,
1793 });
1794 }
1795
1796 Ok(AcpiPciNamespace {
1797 link_allocator: Mutex::new(PciLinkAllocator::default()),
1798 roots,
1799 })
1800}
1801
1802fn read_pci_routing_table(
1803 interpreter: &Interpreter<AcpiHandler>,
1804 root_path: &str,
1805) -> Result<Option<PciRoutingTable>, AcpiError> {
1806 let prt_path = AmlName::from_str(&format!("{root_path}._PRT")).map_err(AcpiError::Aml)?;
1807 match PciRoutingTable::from_prt_path(prt_path, interpreter) {
1808 Ok(prt) => Ok(Some(prt)),
1809 Err(AmlError::ObjectDoesNotExist(_)) | Err(AmlError::LevelDoesNotExist(_)) => Ok(None),
1810 Err(err) => Err(AcpiError::Aml(err)),
1811 }
1812}
1813
1814fn read_pci_link_routing_table(
1815 interpreter: &Interpreter<AcpiHandler>,
1816 root_path: &str,
1817) -> Result<Option<PciLinkRoutingTable>, AcpiError> {
1818 let prt_path = AmlName::from_str(&format!("{root_path}._PRT")).map_err(AcpiError::Aml)?;
1819 match PciLinkRoutingTable::from_prt_path(prt_path, interpreter) {
1820 Ok(prt) => Ok(Some(prt)),
1821 Err(AmlError::ObjectDoesNotExist(_)) | Err(AmlError::LevelDoesNotExist(_)) => Ok(None),
1822 Err(err) => Err(AcpiError::Aml(err)),
1823 }
1824}
1825
1826fn is_pci_root(interpreter: &Interpreter<AcpiHandler>, path: &AmlName) -> bool {
1827 has_pci_root_id(interpreter, path, "_HID") || has_pci_root_id(interpreter, path, "_CID")
1828}
1829
1830fn has_pci_root_id(interpreter: &Interpreter<AcpiHandler>, path: &AmlName, name: &str) -> bool {
1831 let Ok(Some(value)) = eval_child(interpreter, path, name) else {
1832 return false;
1833 };
1834 object_matches_pci_root_id(&value)
1835}
1836
1837fn object_matches_pci_root_id(value: &Object) -> bool {
1838 match value {
1839 Object::String(id) => matches!(id.as_str(), "PNP0A03" | "PNP0A08"),
1840 Object::Integer(id) => {
1841 let id = decode_eisa_id(*id as u32);
1842 matches!(id.as_deref(), Some("PNP0A03" | "PNP0A08"))
1843 }
1844 Object::Package(values) => values.iter().any(|value| object_matches_pci_root_id(value)),
1845 _ => false,
1846 }
1847}
1848
1849fn eval_integer_child(
1850 interpreter: &Interpreter<AcpiHandler>,
1851 path: &AmlName,
1852 name: &str,
1853) -> Result<Option<u64>, AmlError> {
1854 eval_child(interpreter, path, name)?
1855 .map(|value| value.as_integer())
1856 .transpose()
1857}
1858
1859fn eval_child(
1860 interpreter: &Interpreter<AcpiHandler>,
1861 path: &AmlName,
1862 name: &str,
1863) -> Result<Option<Rc<Object>>, AmlError> {
1864 match eval_wrapped_child(interpreter, path, name)? {
1865 Some(value) => Ok(Some(Rc::new((*value).clone()))),
1866 None => Ok(None),
1867 }
1868}
1869
1870fn eval_wrapped_child(
1871 interpreter: &Interpreter<AcpiHandler>,
1872 path: &AmlName,
1873 name: &str,
1874) -> Result<Option<acpi::aml::object::WrappedObject>, AmlError> {
1875 let child = AmlName::from_str(name)?.resolve(path)?;
1876 interpreter.evaluate_if_present(child, Vec::new())
1877}
1878
1879fn decode_eisa_id(raw: u32) -> Option<String> {
1880 if raw == 0 {
1881 return None;
1882 }
1883 let bytes = raw.to_le_bytes();
1884 let chars = [
1885 ((bytes[0] >> 2) & 0x1f).wrapping_add(b'@'),
1886 (((bytes[0] & 0x03) << 3) | (bytes[1] >> 5)).wrapping_add(b'@'),
1887 (bytes[1] & 0x1f).wrapping_add(b'@'),
1888 ];
1889 if !chars.iter().all(u8::is_ascii_uppercase) {
1890 return None;
1891 }
1892 Some(format!(
1893 "{}{}{}{:02X}{:02X}",
1894 chars[0] as char, chars[1] as char, chars[2] as char, bytes[2], bytes[3]
1895 ))
1896}
1897
1898#[derive(Debug)]
1899struct PciLinkRoutingTable {
1900 entries: Vec<PciLinkRoute>,
1901}
1902
1903#[derive(Debug)]
1904struct PciLinkRoute {
1905 device: u16,
1906 function: u16,
1907 pin: Pin,
1908 link: AmlName,
1909 source_index: usize,
1910}
1911
1912impl PciLinkRoutingTable {
1913 fn from_prt_path(
1914 prt_path: AmlName,
1915 interpreter: &Interpreter<AcpiHandler>,
1916 ) -> Result<Self, AmlError> {
1917 let prt = interpreter.evaluate(prt_path.clone(), Vec::new())?;
1918 let Object::Package(ref entries) = *prt else {
1919 return Err(AmlError::InvalidOperationOnObject {
1920 op: acpi::aml::Operation::DecodePrt,
1921 typ: prt.typ(),
1922 });
1923 };
1924
1925 let mut routes = Vec::new();
1926 for entry in entries {
1927 let Object::Package(ref package) = **entry else {
1928 return Err(AmlError::InvalidOperationOnObject {
1929 op: acpi::aml::Operation::DecodePrt,
1930 typ: entry.typ(),
1931 });
1932 };
1933 if package.len() != 4 {
1934 return Err(AmlError::UnexpectedResourceType);
1935 }
1936
1937 let Object::Integer(address) = *package[0] else {
1938 return Err(AmlError::PrtInvalidAddress);
1939 };
1940 let entry_device =
1941 u16::try_from((address >> 16) & 0xffff).map_err(|_| AmlError::PrtInvalidAddress)?;
1942 let entry_function =
1943 u16::try_from(address & 0xffff).map_err(|_| AmlError::PrtInvalidAddress)?;
1944 let entry_pin = match *package[1] {
1945 Object::Integer(0) => Pin::IntA,
1946 Object::Integer(1) => Pin::IntB,
1947 Object::Integer(2) => Pin::IntC,
1948 Object::Integer(3) => Pin::IntD,
1949 _ => return Err(AmlError::PrtInvalidPin),
1950 };
1951 let Object::String(ref source) = *package[2] else {
1952 continue;
1953 };
1954 let Object::Integer(source_index) = *package[3] else {
1955 return Err(AmlError::PrtInvalidSource);
1956 };
1957 let source_index =
1958 usize::try_from(source_index).map_err(|_| AmlError::PrtInvalidSource)?;
1959 let link = interpreter
1960 .namespace
1961 .lock()
1962 .search_for_level(&AmlName::from_str(source)?, &prt_path)?;
1963 routes.push(PciLinkRoute {
1964 device: entry_device,
1965 function: entry_function,
1966 pin: entry_pin,
1967 link,
1968 source_index,
1969 });
1970 }
1971
1972 Ok(Self { entries: routes })
1973 }
1974
1975 fn route(
1976 &self,
1977 device: u16,
1978 function: u16,
1979 pin: Pin,
1980 interpreter: &Interpreter<AcpiHandler>,
1981 handler: &AcpiHandler,
1982 allocator: &mut PciLinkAllocator,
1983 ) -> Result<Option<IrqDescriptor>, AmlError> {
1984 let Some(route) = self.entries.iter().find(|entry| {
1985 entry.device == device
1986 && (entry.function == 0xffff || entry.function == function)
1987 && entry.pin == pin
1988 }) else {
1989 return Ok(None);
1990 };
1991
1992 resolve_pci_link_irq(
1993 interpreter,
1994 handler,
1995 allocator,
1996 &route.link,
1997 route.source_index,
1998 )
1999 }
2000}
2001
2002#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2003enum LinkIrqResourceKind {
2004 SmallIrq,
2005 ExtendedIrq,
2006}
2007
2008#[derive(Clone, Debug)]
2009struct LinkIrqResource {
2010 kind: LinkIrqResourceKind,
2011 descriptor: IrqDescriptor,
2012 irqs: Vec<u32>,
2013}
2014
2015struct LinkIrqSelection<'a> {
2016 resource: &'a LinkIrqResource,
2017 irq: u32,
2018 needs_programming: bool,
2019}
2020
2021#[derive(Default)]
2022struct PciLinkAllocator {
2023 assigned: BTreeMap<String, u32>,
2024 irq_use_count: BTreeMap<u32, usize>,
2025}
2026
2027impl PciLinkAllocator {
2028 fn assigned_irq(&self, link: &AmlName) -> Option<u32> {
2029 self.assigned.get(&link.as_string()).copied()
2030 }
2031
2032 fn commit(&mut self, link: &AmlName, irq: u32) {
2033 let key = link.as_string();
2034 match self.assigned.insert(key, irq) {
2035 Some(old_irq) if old_irq == irq => return,
2036 Some(old_irq) => {
2037 if let Some(count) = self.irq_use_count.get_mut(&old_irq) {
2038 *count = count.saturating_sub(1);
2039 }
2040 }
2041 None => {}
2042 }
2043 *self.irq_use_count.entry(irq).or_default() += 1;
2044 }
2045
2046 fn penalty(&self, irq: u32) -> usize {
2047 let isa_penalty = match irq {
2048 0..=2 => usize::MAX / 2,
2049 3..=8 => 16 * 16 * 16 * 16,
2050 9..=11 => 0,
2051 12..=15 => 16 * 16 * 16 * 16 * 16,
2052 _ => 0,
2053 };
2054 isa_penalty + self.irq_use_count.get(&irq).copied().unwrap_or(0) * 16 * 16 * 16
2055 }
2056}
2057
2058fn resolve_pci_link_irq(
2059 interpreter: &Interpreter<AcpiHandler>,
2060 handler: &AcpiHandler,
2061 allocator: &mut PciLinkAllocator,
2062 link: &AmlName,
2063 source_index: usize,
2064) -> Result<Option<IrqDescriptor>, AmlError> {
2065 let current = evaluate_link_irq_resource(interpreter, link, "_CRS", source_index)?;
2066 let possible = evaluate_link_irq_resource(interpreter, link, "_PRS", source_index)?;
2067 let Some(selection) = select_pci_link_irq(link, current.as_ref(), possible.as_ref(), allocator)
2068 else {
2069 return Ok(None);
2070 };
2071
2072 if selection.needs_programming {
2073 let srs = build_link_srs_buffer(selection.resource, selection.irq)?;
2074 let srs_path = AmlName::from_str("_SRS")?.resolve(link)?;
2075 if let Err(err) = interpreter.evaluate(srs_path.clone(), vec![Object::Buffer(srs).wrap()]) {
2076 if is_buffer_field_to_field_unit_store_gap(&err) {
2077 let _ = interpreter.namespace.lock().remove_level(srs_path);
2078 program_known_pci_link_field(interpreter, handler, link, selection.irq)?;
2082 } else {
2083 let _ = interpreter.namespace.lock().remove_level(srs_path);
2084 return Err(err);
2085 }
2086 }
2087 }
2088
2089 allocator.commit(link, selection.irq);
2090 Ok(Some(selection.resource.descriptor_for_irq(selection.irq)))
2091}
2092
2093fn evaluate_link_irq_resource(
2094 interpreter: &Interpreter<AcpiHandler>,
2095 link: &AmlName,
2096 method: &str,
2097 source_index: usize,
2098) -> Result<Option<LinkIrqResource>, AmlError> {
2099 let path = AmlName::from_str(method)?.resolve(link)?;
2100 let value = match interpreter.evaluate_if_present(path.clone(), Vec::new()) {
2101 Ok(Some(value)) => value,
2102 Ok(None) => return Ok(None),
2103 Err(err) if method == "_CRS" && is_buffer_field_to_field_unit_store_gap(&err) => {
2104 let _ = interpreter.namespace.lock().remove_level(path);
2105 return Ok(None);
2106 }
2107 Err(err) => {
2108 let _ = interpreter.namespace.lock().remove_level(path);
2109 return Err(err);
2110 }
2111 };
2112 let resources = parse_link_irq_resources(&value)?;
2113 Ok(resources.into_iter().nth(source_index))
2114}
2115
2116fn is_buffer_field_to_field_unit_store_gap(err: &AmlError) -> bool {
2117 matches!(
2118 err,
2119 AmlError::ObjectNotOfExpectedType {
2120 expected: ObjectType::Integer,
2121 got: ObjectType::BufferField,
2122 }
2123 )
2124}
2125
2126fn program_known_pci_link_field(
2127 interpreter: &Interpreter<AcpiHandler>,
2128 handler: &AcpiHandler,
2129 link: &AmlName,
2130 irq: u32,
2131) -> Result<(), AmlError> {
2132 let Some(field_path) = known_pci_link_irq_field(interpreter, link) else {
2133 return Err(AmlError::ObjectNotOfExpectedType {
2134 expected: ObjectType::Integer,
2135 got: ObjectType::BufferField,
2136 });
2137 };
2138 let field = interpreter.namespace.lock().get(field_path)?.clone();
2139 let Object::FieldUnit(ref field) = *field else {
2140 return Err(AmlError::ObjectNotOfExpectedType {
2141 expected: ObjectType::FieldUnit,
2142 got: field.typ(),
2143 });
2144 };
2145 write_field_unit(interpreter, handler, field, irq as u64)
2146}
2147
2148fn known_pci_link_irq_field(
2149 interpreter: &Interpreter<AcpiHandler>,
2150 link: &AmlName,
2151) -> Option<AmlName> {
2152 let mut namespace = interpreter.namespace.lock();
2153 for field in pci_link_irq_field_candidates(link) {
2154 let path = AmlName::from_str(field).ok()?;
2155 if namespace.get(path.clone()).is_ok() {
2156 return Some(path);
2157 }
2158 }
2159 None
2160}
2161
2162fn pci_link_irq_field_candidates(link: &AmlName) -> &'static [&'static str] {
2163 match link.as_string().rsplit('.').next().unwrap_or_default() {
2164 "LNKA" => &["\\_SB.PRQA", "\\_SB.PRQ0"],
2165 "LNKB" => &["\\_SB.PRQB", "\\_SB.PRQ1"],
2166 "LNKC" => &["\\_SB.PRQC", "\\_SB.PRQ2"],
2167 "LNKD" => &["\\_SB.PRQD", "\\_SB.PRQ3"],
2168 "LNKE" => &["\\_SB.PRQE"],
2169 "LNKF" => &["\\_SB.PRQF"],
2170 "LNKG" => &["\\_SB.PRQG"],
2171 "LNKH" => &["\\_SB.PRQH"],
2172 _ => &[],
2173 }
2174}
2175
2176fn write_field_unit(
2177 interpreter: &Interpreter<AcpiHandler>,
2178 handler: &AcpiHandler,
2179 field: &FieldUnit,
2180 value: u64,
2181) -> Result<(), AmlError> {
2182 let access_width_bits = field.flags.access_type_bytes()? * 8;
2183 let FieldUnitKind::Normal { ref region } = field.kind else {
2184 return Err(AmlError::LibUnimplemented);
2185 };
2186 let Object::OpRegion(ref region) = **region else {
2187 return Err(AmlError::ObjectNotOfExpectedType {
2188 expected: ObjectType::OpRegion,
2189 got: region.typ(),
2190 });
2191 };
2192
2193 let value_bytes = value.to_le_bytes();
2194 let native_accesses =
2195 (field.bit_length + (field.bit_index % access_width_bits)).div_ceil(access_width_bits);
2196 let mut written_so_far = 0;
2197
2198 for i in 0..native_accesses {
2199 let aligned_bit = align_down(field.bit_index + i * access_width_bits, access_width_bits);
2200 let dst_index = if i == 0 {
2201 field.bit_index % access_width_bits
2202 } else {
2203 0
2204 };
2205 let remaining = field.bit_length - written_so_far;
2206 let length = if i == 0 {
2207 usize::min(
2208 remaining,
2209 access_width_bits - (field.bit_index % access_width_bits),
2210 )
2211 } else {
2212 usize::min(remaining, access_width_bits)
2213 };
2214
2215 let mut bytes = if dst_index > 0 || remaining < access_width_bits {
2216 match field.flags.update_rule() {
2217 FieldUpdateRule::Preserve => read_native_region(
2218 interpreter,
2219 handler,
2220 region,
2221 aligned_bit / 8,
2222 access_width_bits / 8,
2223 )?
2224 .to_le_bytes(),
2225 FieldUpdateRule::WriteAsOnes => [0xff; 8],
2226 FieldUpdateRule::WriteAsZeros => [0; 8],
2227 }
2228 } else {
2229 [0; 8]
2230 };
2231
2232 copy_bits(&value_bytes, written_so_far, &mut bytes, dst_index, length);
2233 write_native_region(
2234 interpreter,
2235 handler,
2236 region,
2237 aligned_bit / 8,
2238 access_width_bits / 8,
2239 u64::from_le_bytes(bytes),
2240 )?;
2241 written_so_far += length;
2242 }
2243
2244 Ok(())
2245}
2246
2247fn read_native_region(
2248 interpreter: &Interpreter<AcpiHandler>,
2249 handler: &AcpiHandler,
2250 region: &OpRegion,
2251 offset: usize,
2252 length: usize,
2253) -> Result<u64, AmlError> {
2254 match region.space {
2255 RegionSpace::SystemMemory => {
2256 let address = region.base as usize + offset;
2257 match length {
2258 1 => Ok(u64::from(handler.read_u8(address))),
2259 2 => Ok(u64::from(handler.read_u16(address))),
2260 4 => Ok(u64::from(handler.read_u32(address))),
2261 8 => Ok(handler.read_u64(address)),
2262 _ => Err(AmlError::InvalidFieldFlags),
2263 }
2264 }
2265 RegionSpace::SystemIO => {
2266 let address = region.base as u16 + offset as u16;
2267 match length {
2268 1 => Ok(u64::from(handler.read_io_u8(address))),
2269 2 => Ok(u64::from(handler.read_io_u16(address))),
2270 4 => Ok(u64::from(handler.read_io_u32(address))),
2271 _ => Err(AmlError::InvalidFieldFlags),
2272 }
2273 }
2274 RegionSpace::PciConfig => {
2275 let address = pci_address_for_region(interpreter, region)?;
2276 let offset = region.base as u16 + offset as u16;
2277 match length {
2278 1 => Ok(u64::from(handler.read_pci_u8(address, offset))),
2279 2 => Ok(u64::from(handler.read_pci_u16(address, offset))),
2280 4 => Ok(u64::from(handler.read_pci_u32(address, offset))),
2281 _ => Err(AmlError::InvalidFieldFlags),
2282 }
2283 }
2284 _ => Err(AmlError::NoHandlerForRegionAccess(region.space)),
2285 }
2286}
2287
2288fn write_native_region(
2289 interpreter: &Interpreter<AcpiHandler>,
2290 handler: &AcpiHandler,
2291 region: &OpRegion,
2292 offset: usize,
2293 length: usize,
2294 value: u64,
2295) -> Result<(), AmlError> {
2296 match region.space {
2297 RegionSpace::SystemMemory => {
2298 let address = region.base as usize + offset;
2299 match length {
2300 1 => handler.write_u8(address, value as u8),
2301 2 => handler.write_u16(address, value as u16),
2302 4 => handler.write_u32(address, value as u32),
2303 8 => handler.write_u64(address, value),
2304 _ => return Err(AmlError::InvalidFieldFlags),
2305 }
2306 Ok(())
2307 }
2308 RegionSpace::SystemIO => {
2309 let address = region.base as u16 + offset as u16;
2310 match length {
2311 1 => handler.write_io_u8(address, value as u8),
2312 2 => handler.write_io_u16(address, value as u16),
2313 4 => handler.write_io_u32(address, value as u32),
2314 _ => return Err(AmlError::InvalidFieldFlags),
2315 }
2316 Ok(())
2317 }
2318 RegionSpace::PciConfig => {
2319 let address = pci_address_for_region(interpreter, region)?;
2320 let offset = region.base as u16 + offset as u16;
2321 match length {
2322 1 => handler.write_pci_u8(address, offset, value as u8),
2323 2 => handler.write_pci_u16(address, offset, value as u16),
2324 4 => handler.write_pci_u32(address, offset, value as u32),
2325 _ => return Err(AmlError::InvalidFieldFlags),
2326 }
2327 Ok(())
2328 }
2329 _ => Err(AmlError::NoHandlerForRegionAccess(region.space)),
2330 }
2331}
2332
2333fn pci_address_for_region(
2334 interpreter: &Interpreter<AcpiHandler>,
2335 region: &OpRegion,
2336) -> Result<acpi::PciAddress, AmlError> {
2337 let path = ®ion.parent_device_path;
2338 let segment = eval_integer_child(interpreter, path, "_SEG")?.unwrap_or(0) as u16;
2339 let bus = eval_integer_child(interpreter, path, "_BBN")?.unwrap_or(0) as u8;
2340 let address = eval_integer_child(interpreter, path, "_ADR")?.unwrap_or(0);
2341 Ok(acpi::PciAddress::new(
2342 segment,
2343 bus,
2344 ((address >> 16) & 0xff) as u8,
2345 (address & 0xff) as u8,
2346 ))
2347}
2348
2349fn copy_bits(src: &[u8], src_offset: usize, dst: &mut [u8], dst_offset: usize, length: usize) {
2350 for bit in 0..length {
2351 let src_bit = src_offset + bit;
2352 let dst_bit = dst_offset + bit;
2353 let is_set = src[src_bit / 8] & (1 << (src_bit % 8)) != 0;
2354 if is_set {
2355 dst[dst_bit / 8] |= 1 << (dst_bit % 8);
2356 } else {
2357 dst[dst_bit / 8] &= !(1 << (dst_bit % 8));
2358 }
2359 }
2360}
2361
2362fn align_down(value: usize, align: usize) -> usize {
2363 assert!(align.is_power_of_two());
2364 value & !(align - 1)
2365}
2366
2367fn parse_link_irq_resources(
2368 value: &acpi::aml::object::WrappedObject,
2369) -> Result<Vec<LinkIrqResource>, AmlError> {
2370 let Object::Buffer(ref bytes) = **value else {
2371 return Err(AmlError::InvalidOperationOnObject {
2372 op: acpi::aml::Operation::ParseResource,
2373 typ: value.typ(),
2374 });
2375 };
2376
2377 let mut resources = Vec::new();
2378 let mut rest = bytes.as_slice();
2379 while !rest.is_empty() {
2380 if rest[0] & 0x80 != 0 {
2381 if rest.len() < 3 {
2382 return Err(AmlError::InvalidResourceDescriptor);
2383 }
2384 let length = usize::from(u16::from_le_bytes([rest[1], rest[2]]));
2385 if rest.len() < length + 3 {
2386 return Err(AmlError::InvalidResourceDescriptor);
2387 }
2388 let descriptor = &rest[..length + 3];
2389 if rest[0] & 0x7f == 0x09 {
2390 resources.push(parse_extended_irq_resource(descriptor)?);
2391 }
2392 rest = &rest[length + 3..];
2393 } else {
2394 let length = usize::from(rest[0] & 0b111);
2395 if rest.len() < length + 1 {
2396 return Err(AmlError::InvalidResourceDescriptor);
2397 }
2398 let descriptor = &rest[..length + 1];
2399 match (rest[0] >> 3) & 0x0f {
2400 0x04 => resources.push(parse_small_irq_resource(descriptor)?),
2401 0x0f => break,
2402 _ => {}
2403 }
2404 rest = &rest[length + 1..];
2405 }
2406 }
2407 Ok(resources)
2408}
2409
2410fn parse_extended_irq_resource(bytes: &[u8]) -> Result<LinkIrqResource, AmlError> {
2411 if bytes.len() < 5 {
2412 return Err(AmlError::InvalidResourceDescriptor);
2413 }
2414 let count = usize::from(bytes[4]);
2415 if bytes.len() < 5 + count * 4 {
2416 return Err(AmlError::InvalidResourceDescriptor);
2417 }
2418
2419 let mut irqs = Vec::new();
2420 for idx in 0..count {
2421 let start = 5 + idx * 4;
2422 irqs.push(u32::from_le_bytes([
2423 bytes[start],
2424 bytes[start + 1],
2425 bytes[start + 2],
2426 bytes[start + 3],
2427 ]));
2428 }
2429
2430 Ok(LinkIrqResource {
2431 kind: LinkIrqResourceKind::ExtendedIrq,
2432 descriptor: IrqDescriptor {
2433 is_consumer: bytes[3] & 0b0000_0001 != 0,
2434 trigger: if bytes[3] & 0b0000_0010 != 0 {
2435 InterruptTrigger::Edge
2436 } else {
2437 InterruptTrigger::Level
2438 },
2439 polarity: if bytes[3] & 0b0000_0100 != 0 {
2440 InterruptPolarity::ActiveLow
2441 } else {
2442 InterruptPolarity::ActiveHigh
2443 },
2444 is_shared: bytes[3] & 0b0000_1000 != 0,
2445 is_wake_capable: bytes[3] & 0b0001_0000 != 0,
2446 irq: irqs.first().copied().unwrap_or(0),
2447 },
2448 irqs,
2449 })
2450}
2451
2452fn parse_small_irq_resource(bytes: &[u8]) -> Result<LinkIrqResource, AmlError> {
2453 if bytes.len() != 3 && bytes.len() != 4 {
2454 return Err(AmlError::InvalidResourceDescriptor);
2455 }
2456
2457 let mask = u16::from_le_bytes([bytes[1], bytes[2]]);
2458 let mut irqs = Vec::new();
2459 for irq in 0..16 {
2460 if mask & (1 << irq) != 0 {
2461 irqs.push(irq);
2462 }
2463 }
2464
2465 let (trigger, polarity, is_shared, is_wake_capable) = if bytes.len() == 4 {
2466 (
2467 if bytes[3] & 0b0000_0001 != 0 {
2468 InterruptTrigger::Edge
2469 } else {
2470 InterruptTrigger::Level
2471 },
2472 if bytes[3] & 0b0000_1000 != 0 {
2473 InterruptPolarity::ActiveLow
2474 } else {
2475 InterruptPolarity::ActiveHigh
2476 },
2477 bytes[3] & 0b0001_0000 != 0,
2478 bytes[3] & 0b0010_0000 != 0,
2479 )
2480 } else {
2481 (
2482 InterruptTrigger::Edge,
2483 InterruptPolarity::ActiveHigh,
2484 false,
2485 false,
2486 )
2487 };
2488
2489 Ok(LinkIrqResource {
2490 kind: LinkIrqResourceKind::SmallIrq,
2491 descriptor: IrqDescriptor {
2492 is_consumer: false,
2493 trigger,
2494 polarity,
2495 is_shared,
2496 is_wake_capable,
2497 irq: u32::from(mask),
2498 },
2499 irqs,
2500 })
2501}
2502
2503fn select_pci_link_irq<'a>(
2504 link: &AmlName,
2505 current: Option<&'a LinkIrqResource>,
2506 possible: Option<&'a LinkIrqResource>,
2507 allocator: &PciLinkAllocator,
2508) -> Option<LinkIrqSelection<'a>> {
2509 if let Some(irq) = allocator.assigned_irq(link) {
2510 let resource = possible
2511 .filter(|possible| possible.irqs.contains(&irq))
2512 .or(current.filter(|current| current.irqs.contains(&irq)))?;
2513 return Some(LinkIrqSelection {
2514 resource,
2515 irq,
2516 needs_programming: current.is_none_or(|current| current.irqs.first() != Some(&irq)),
2517 });
2518 }
2519
2520 if let Some(current) = current
2521 && let Some(irq) = current.irqs.first().copied().filter(|irq| *irq != 0)
2522 && possible.is_none_or(|possible| possible.irqs.contains(&irq))
2523 {
2524 return Some(LinkIrqSelection {
2525 resource: possible.unwrap_or(current),
2526 irq,
2527 needs_programming: false,
2528 });
2529 }
2530
2531 let possible = possible?;
2532 let irq = preferred_pci_link_irq(&possible.irqs, allocator)?;
2533 Some(LinkIrqSelection {
2534 resource: possible,
2535 irq,
2536 needs_programming: true,
2537 })
2538}
2539
2540fn preferred_pci_link_irq(irqs: &[u32], allocator: &PciLinkAllocator) -> Option<u32> {
2541 irqs.iter()
2542 .copied()
2543 .filter(|irq| *irq != 0)
2544 .min_by_key(|irq| (allocator.penalty(*irq), link_irq_tiebreaker(*irq)))
2545}
2546
2547fn link_irq_tiebreaker(irq: u32) -> usize {
2548 match irq {
2549 10 => 0,
2550 11 => 1,
2551 9 => 2,
2552 16.. => 3 + irq as usize,
2553 _ => 1024 + irq as usize,
2554 }
2555}
2556
2557fn build_link_srs_buffer(resource: &LinkIrqResource, irq: u32) -> Result<Vec<u8>, AmlError> {
2558 match resource.kind {
2559 LinkIrqResourceKind::ExtendedIrq => {
2560 let mut buffer = Vec::new();
2561 buffer.extend_from_slice(&[
2562 0x89,
2563 0x06,
2564 0x00,
2565 extended_irq_flags(&resource.descriptor),
2566 1,
2567 ]);
2568 buffer.extend_from_slice(&irq.to_le_bytes());
2569 buffer.extend_from_slice(&[0x79, 0x00]);
2570 Ok(buffer)
2571 }
2572 LinkIrqResourceKind::SmallIrq => {
2573 if irq >= 16 {
2574 return Err(AmlError::InvalidResourceDescriptor);
2575 }
2576 let mask = 1u16 << irq;
2577 let mut buffer = Vec::new();
2578 buffer.push((0x04 << 3) | 3);
2579 buffer.extend_from_slice(&mask.to_le_bytes());
2580 buffer.push(small_irq_flags(&resource.descriptor));
2581 buffer.extend_from_slice(&[0x79, 0x00]);
2582 Ok(buffer)
2583 }
2584 }
2585}
2586
2587impl LinkIrqResource {
2588 fn descriptor_for_irq(&self, irq: u32) -> IrqDescriptor {
2589 let mut descriptor = self.descriptor.clone();
2590 descriptor.irq = irq;
2591 descriptor
2592 }
2593}
2594
2595fn extended_irq_flags(descriptor: &IrqDescriptor) -> u8 {
2596 let mut flags = 0;
2597 if descriptor.is_consumer {
2598 flags |= 1 << 0;
2599 }
2600 if descriptor.trigger == InterruptTrigger::Edge {
2601 flags |= 1 << 1;
2602 }
2603 if descriptor.polarity == InterruptPolarity::ActiveLow {
2604 flags |= 1 << 2;
2605 }
2606 if descriptor.is_shared {
2607 flags |= 1 << 3;
2608 }
2609 if descriptor.is_wake_capable {
2610 flags |= 1 << 4;
2611 }
2612 flags
2613}
2614
2615fn small_irq_flags(descriptor: &IrqDescriptor) -> u8 {
2616 let mut flags = 0;
2617 if descriptor.trigger == InterruptTrigger::Edge {
2618 flags |= 1 << 0;
2619 }
2620 if descriptor.polarity == InterruptPolarity::ActiveLow {
2621 flags |= 1 << 3;
2622 }
2623 if descriptor.is_shared {
2624 flags |= 1 << 4;
2625 }
2626 if descriptor.is_wake_capable {
2627 flags |= 1 << 5;
2628 }
2629 flags
2630}
2631
2632fn acpi_pin(interrupt_pin: u8) -> Result<Pin, OnProbeError> {
2633 match interrupt_pin {
2634 1 => Ok(Pin::IntA),
2635 2 => Ok(Pin::IntB),
2636 3 => Ok(Pin::IntC),
2637 4 => Ok(Pin::IntD),
2638 _ => Err(OnProbeError::other(format!(
2639 "invalid PCI interrupt pin {interrupt_pin}"
2640 ))),
2641 }
2642}
2643
2644fn irq_descriptor_gsi(descriptor: &IrqDescriptor) -> Option<u32> {
2645 let irq = descriptor.irq;
2646 if !descriptor.is_consumer && irq.count_ones() == 1 && irq <= u16::MAX as u32 {
2647 Some(irq.trailing_zeros())
2648 } else {
2649 Some(irq)
2650 }
2651}
2652
2653fn pci_irq_descriptor_gsi(descriptor: &IrqDescriptor) -> Option<u32> {
2654 Some(descriptor.irq)
2655}
2656
2657fn route_with_irq_descriptor_flags(
2658 route: AcpiGsiRoute,
2659 descriptor: &IrqDescriptor,
2660) -> AcpiGsiRoute {
2661 AcpiGsiRoute {
2662 trigger: irq_trigger(descriptor.trigger),
2663 polarity: irq_polarity(descriptor.polarity),
2664 ..route
2665 }
2666}
2667
2668fn irq_trigger(trigger: acpi::aml::resource::InterruptTrigger) -> AcpiIrqTrigger {
2669 match trigger {
2670 acpi::aml::resource::InterruptTrigger::Edge => AcpiIrqTrigger::Edge,
2671 acpi::aml::resource::InterruptTrigger::Level => AcpiIrqTrigger::Level,
2672 }
2673}
2674
2675fn irq_polarity(polarity: acpi::aml::resource::InterruptPolarity) -> AcpiIrqPolarity {
2676 match polarity {
2677 acpi::aml::resource::InterruptPolarity::ActiveHigh => AcpiIrqPolarity::ActiveHigh,
2678 acpi::aml::resource::InterruptPolarity::ActiveLow => AcpiIrqPolarity::ActiveLow,
2679 }
2680}
2681
2682#[cfg(target_arch = "x86_64")]
2683fn pci_legacy_read_u8(address: acpi::PciAddress, offset: u16) -> Option<u8> {
2684 let value = pci_legacy_read_aligned_u32(address, offset)?;
2685 let shift = u32::from(offset & 0b11) * 8;
2686 Some((value >> shift) as u8)
2687}
2688
2689#[cfg(not(target_arch = "x86_64"))]
2690fn pci_legacy_read_u8(_address: acpi::PciAddress, _offset: u16) -> Option<u8> {
2691 None
2692}
2693
2694#[cfg(target_arch = "x86_64")]
2695fn pci_legacy_write_u8(address: acpi::PciAddress, offset: u16, value: u8) {
2696 let Some(old) = pci_legacy_read_aligned_u32(address, offset) else {
2697 return;
2698 };
2699 let shift = u32::from(offset & 0b11) * 8;
2700 let mask = 0xff_u32 << shift;
2701 let new = (old & !mask) | (u32::from(value) << shift);
2702 pci_legacy_write_aligned_u32(address, offset, new);
2703}
2704
2705#[cfg(not(target_arch = "x86_64"))]
2706fn pci_legacy_write_u8(_address: acpi::PciAddress, _offset: u16, _value: u8) {}
2707
2708#[cfg(target_arch = "x86_64")]
2709fn pci_legacy_config_address(address: acpi::PciAddress, offset: u16) -> Option<u32> {
2710 if address.segment() != 0 || offset >= 256 {
2711 return None;
2712 }
2713
2714 Some(
2715 0x8000_0000
2716 | (u32::from(address.bus()) << 16)
2717 | (u32::from(address.device()) << 11)
2718 | (u32::from(address.function()) << 8)
2719 | u32::from(offset & !0b11),
2720 )
2721}
2722
2723#[cfg(target_arch = "x86_64")]
2724fn pci_legacy_read_aligned_u32(address: acpi::PciAddress, offset: u16) -> Option<u32> {
2725 let config_address = pci_legacy_config_address(address, offset)?;
2726 unsafe {
2727 x86::io::outl(0xcf8, config_address);
2728 Some(x86::io::inl(0xcfc))
2729 }
2730}
2731
2732#[cfg(target_arch = "x86_64")]
2733fn pci_legacy_write_aligned_u32(address: acpi::PciAddress, offset: u16, value: u32) {
2734 if let Some(config_address) = pci_legacy_config_address(address, offset) {
2735 unsafe {
2736 x86::io::outl(0xcf8, config_address);
2737 x86::io::outl(0xcfc, value);
2738 }
2739 }
2740}
2741
2742pub fn acpi_trigger(trigger: TriggerMode) -> AcpiIrqTrigger {
2743 match trigger {
2744 TriggerMode::Edge => AcpiIrqTrigger::Edge,
2745 TriggerMode::Level => AcpiIrqTrigger::Level,
2746 _ => AcpiIrqTrigger::Level,
2747 }
2748}
2749
2750pub fn acpi_polarity(polarity: Polarity) -> AcpiIrqPolarity {
2751 match polarity {
2752 Polarity::ActiveHigh => AcpiIrqPolarity::ActiveHigh,
2753 Polarity::ActiveLow => AcpiIrqPolarity::ActiveLow,
2754 _ => AcpiIrqPolarity::ActiveLow,
2755 }
2756}
2757
2758#[cfg(target_arch = "x86_64")]
2759fn read_io_u8(port: u16) -> u8 {
2760 unsafe { x86::io::inb(port) }
2761}
2762
2763#[cfg(not(target_arch = "x86_64"))]
2764fn read_io_u8(_port: u16) -> u8 {
2765 0
2766}
2767
2768#[cfg(target_arch = "x86_64")]
2769fn read_io_u16(port: u16) -> u16 {
2770 unsafe { x86::io::inw(port) }
2771}
2772
2773#[cfg(not(target_arch = "x86_64"))]
2774fn read_io_u16(_port: u16) -> u16 {
2775 0
2776}
2777
2778#[cfg(target_arch = "x86_64")]
2779fn read_io_u32(port: u16) -> u32 {
2780 unsafe { x86::io::inl(port) }
2781}
2782
2783#[cfg(not(target_arch = "x86_64"))]
2784fn read_io_u32(_port: u16) -> u32 {
2785 0
2786}
2787
2788#[cfg(target_arch = "x86_64")]
2789fn write_io_u8(port: u16, value: u8) {
2790 unsafe { x86::io::outb(port, value) }
2791}
2792
2793#[cfg(not(target_arch = "x86_64"))]
2794fn write_io_u8(_port: u16, _value: u8) {}
2795
2796#[cfg(target_arch = "x86_64")]
2797fn write_io_u16(port: u16, value: u16) {
2798 unsafe { x86::io::outw(port, value) }
2799}
2800
2801#[cfg(not(target_arch = "x86_64"))]
2802fn write_io_u16(_port: u16, _value: u16) {}
2803
2804#[cfg(target_arch = "x86_64")]
2805fn write_io_u32(port: u16, value: u32) {
2806 unsafe { x86::io::outl(port, value) }
2807}
2808
2809#[cfg(not(target_arch = "x86_64"))]
2810fn write_io_u32(_port: u16, _value: u32) {}