xref: /cloud-hypervisor/vmm/src/pci_segment.rs (revision c99660a8f9dafb8e9e39e1b52f2f8b7809634a35)
184fc0e09SRob Bradford // Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
284fc0e09SRob Bradford //
384fc0e09SRob Bradford // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
484fc0e09SRob Bradford // Use of this source code is governed by a BSD-style license that can be
584fc0e09SRob Bradford // found in the LICENSE-BSD-3-Clause file.
684fc0e09SRob Bradford //
784fc0e09SRob Bradford // Copyright © 2019 - 2021 Intel Corporation
884fc0e09SRob Bradford //
984fc0e09SRob Bradford // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
1084fc0e09SRob Bradford //
1184fc0e09SRob Bradford 
1288a9f799SRob Bradford use std::sync::{Arc, Mutex};
1388a9f799SRob Bradford 
14adb318f4SRob Bradford use acpi_tables::{aml, Aml};
158b67298aSRob Bradford use arch::layout;
16ae83e3b3SRob Bradford use pci::{DeviceRelocation, PciBdf, PciBus, PciConfigMmio, PciRoot};
1784fc0e09SRob Bradford #[cfg(target_arch = "x86_64")]
1884fc0e09SRob Bradford use pci::{PciConfigIo, PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
198b67298aSRob Bradford use uuid::Uuid;
20cd9d1cf8SRob Bradford use vm_allocator::AddressAllocator;
21954f3dd0SYuanchu Xie use vm_device::BusDeviceSync;
2284fc0e09SRob Bradford 
2388a9f799SRob Bradford use crate::device_manager::{AddressManager, DeviceManagerError, DeviceManagerResult};
2488a9f799SRob Bradford 
2584fc0e09SRob Bradford pub(crate) struct PciSegment {
26080ce9b0SRob Bradford     pub(crate) id: u16,
2784fc0e09SRob Bradford     pub(crate) pci_bus: Arc<Mutex<PciBus>>,
2884fc0e09SRob Bradford     pub(crate) pci_config_mmio: Arc<Mutex<PciConfigMmio>>,
29080ce9b0SRob Bradford     pub(crate) mmio_config_address: u64,
303029fbeaSThomas Barrett     pub(crate) proximity_domain: u32,
3184fc0e09SRob Bradford 
3284fc0e09SRob Bradford     #[cfg(target_arch = "x86_64")]
3384fc0e09SRob Bradford     pub(crate) pci_config_io: Option<Arc<Mutex<PciConfigIo>>>,
3484fc0e09SRob Bradford 
3584fc0e09SRob Bradford     // Bitmap of PCI devices to hotplug.
3684fc0e09SRob Bradford     pub(crate) pci_devices_up: u32,
3784fc0e09SRob Bradford     // Bitmap of PCI devices to hotunplug.
3884fc0e09SRob Bradford     pub(crate) pci_devices_down: u32,
3984fc0e09SRob Bradford     // List of allocated IRQs for each PCI slot.
4084fc0e09SRob Bradford     pub(crate) pci_irq_slots: [u8; 32],
418b67298aSRob Bradford 
428b67298aSRob Bradford     // Device memory covered by this segment
4345b01d59SThomas Barrett     pub(crate) start_of_mem32_area: u64,
4445b01d59SThomas Barrett     pub(crate) end_of_mem32_area: u64,
45cd9d1cf8SRob Bradford 
4645b01d59SThomas Barrett     pub(crate) start_of_mem64_area: u64,
4745b01d59SThomas Barrett     pub(crate) end_of_mem64_area: u64,
4845b01d59SThomas Barrett 
4945b01d59SThomas Barrett     pub(crate) mem32_allocator: Arc<Mutex<AddressAllocator>>,
5045b01d59SThomas Barrett     pub(crate) mem64_allocator: Arc<Mutex<AddressAllocator>>,
5184fc0e09SRob Bradford }
5284fc0e09SRob Bradford 
5384fc0e09SRob Bradford impl PciSegment {
new( id: u16, numa_node: u32, address_manager: &Arc<AddressManager>, mem32_allocator: Arc<Mutex<AddressAllocator>>, mem64_allocator: Arc<Mutex<AddressAllocator>>, pci_irq_slots: &[u8; 32], ) -> DeviceManagerResult<PciSegment>543059ba43SRob Bradford     pub(crate) fn new(
553059ba43SRob Bradford         id: u16,
563029fbeaSThomas Barrett         numa_node: u32,
5784fc0e09SRob Bradford         address_manager: &Arc<AddressManager>,
5845b01d59SThomas Barrett         mem32_allocator: Arc<Mutex<AddressAllocator>>,
5945b01d59SThomas Barrett         mem64_allocator: Arc<Mutex<AddressAllocator>>,
60cf1c2bf0SRob Bradford         pci_irq_slots: &[u8; 32],
6184fc0e09SRob Bradford     ) -> DeviceManagerResult<PciSegment> {
6284fc0e09SRob Bradford         let pci_root = PciRoot::new(None);
6384fc0e09SRob Bradford         let pci_bus = Arc::new(Mutex::new(PciBus::new(
6484fc0e09SRob Bradford             pci_root,
6584fc0e09SRob Bradford             Arc::clone(address_manager) as Arc<dyn DeviceRelocation>,
6684fc0e09SRob Bradford         )));
6784fc0e09SRob Bradford 
6884fc0e09SRob Bradford         let pci_config_mmio = Arc::new(Mutex::new(PciConfigMmio::new(Arc::clone(&pci_bus))));
692f8540daSHenry Wang         let mmio_config_address =
702f8540daSHenry Wang             layout::PCI_MMCONFIG_START.0 + layout::PCI_MMIO_CONFIG_SIZE_PER_SEGMENT * id as u64;
71b55f009bSRob Bradford 
7284fc0e09SRob Bradford         address_manager
7384fc0e09SRob Bradford             .mmio_bus
7484fc0e09SRob Bradford             .insert(
75954f3dd0SYuanchu Xie                 Arc::clone(&pci_config_mmio) as Arc<dyn BusDeviceSync>,
76b55f009bSRob Bradford                 mmio_config_address,
772f8540daSHenry Wang                 layout::PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
7884fc0e09SRob Bradford             )
7984fc0e09SRob Bradford             .map_err(DeviceManagerError::BusError)?;
8084fc0e09SRob Bradford 
8145b01d59SThomas Barrett         let start_of_mem32_area = mem32_allocator.lock().unwrap().base().0;
8245b01d59SThomas Barrett         let end_of_mem32_area = mem32_allocator.lock().unwrap().end().0;
8345b01d59SThomas Barrett 
8445b01d59SThomas Barrett         let start_of_mem64_area = mem64_allocator.lock().unwrap().base().0;
8545b01d59SThomas Barrett         let end_of_mem64_area = mem64_allocator.lock().unwrap().end().0;
86cd9d1cf8SRob Bradford 
87cf1c2bf0SRob Bradford         let segment = PciSegment {
88b55f009bSRob Bradford             id,
8984fc0e09SRob Bradford             pci_bus,
9084fc0e09SRob Bradford             pci_config_mmio,
91b55f009bSRob Bradford             mmio_config_address,
923029fbeaSThomas Barrett             proximity_domain: numa_node,
9384fc0e09SRob Bradford             pci_devices_up: 0,
9484fc0e09SRob Bradford             pci_devices_down: 0,
9584fc0e09SRob Bradford             #[cfg(target_arch = "x86_64")]
963059ba43SRob Bradford             pci_config_io: None,
9745b01d59SThomas Barrett             mem32_allocator,
9845b01d59SThomas Barrett             mem64_allocator,
9945b01d59SThomas Barrett             start_of_mem32_area,
10045b01d59SThomas Barrett             end_of_mem32_area,
10145b01d59SThomas Barrett             start_of_mem64_area,
10245b01d59SThomas Barrett             end_of_mem64_area,
103cf1c2bf0SRob Bradford             pci_irq_slots: *pci_irq_slots,
10484fc0e09SRob Bradford         };
10584fc0e09SRob Bradford 
10684fc0e09SRob Bradford         info!(
10745b01d59SThomas Barrett             "Adding PCI segment: id={}, PCI MMIO config address: 0x{:x}, mem32 area [0x{:x}-0x{:x}, mem64 area [0x{:x}-0x{:x}",
10845b01d59SThomas Barrett             segment.id, segment.mmio_config_address, segment.start_of_mem32_area, segment.end_of_mem32_area, segment.start_of_mem64_area, segment.end_of_mem64_area
10984fc0e09SRob Bradford         );
11084fc0e09SRob Bradford         Ok(segment)
11184fc0e09SRob Bradford     }
11284fc0e09SRob Bradford 
1133059ba43SRob Bradford     #[cfg(target_arch = "x86_64")]
new_default_segment( address_manager: &Arc<AddressManager>, mem32_allocator: Arc<Mutex<AddressAllocator>>, mem64_allocator: Arc<Mutex<AddressAllocator>>, pci_irq_slots: &[u8; 32], ) -> DeviceManagerResult<PciSegment>1143059ba43SRob Bradford     pub(crate) fn new_default_segment(
1153059ba43SRob Bradford         address_manager: &Arc<AddressManager>,
11645b01d59SThomas Barrett         mem32_allocator: Arc<Mutex<AddressAllocator>>,
11745b01d59SThomas Barrett         mem64_allocator: Arc<Mutex<AddressAllocator>>,
118cf1c2bf0SRob Bradford         pci_irq_slots: &[u8; 32],
1193059ba43SRob Bradford     ) -> DeviceManagerResult<PciSegment> {
12045b01d59SThomas Barrett         let mut segment = Self::new(
12145b01d59SThomas Barrett             0,
12245b01d59SThomas Barrett             0,
12345b01d59SThomas Barrett             address_manager,
12445b01d59SThomas Barrett             mem32_allocator,
12545b01d59SThomas Barrett             mem64_allocator,
12645b01d59SThomas Barrett             pci_irq_slots,
12745b01d59SThomas Barrett         )?;
1283059ba43SRob Bradford         let pci_config_io = Arc::new(Mutex::new(PciConfigIo::new(Arc::clone(&segment.pci_bus))));
1293059ba43SRob Bradford 
1303059ba43SRob Bradford         address_manager
1313059ba43SRob Bradford             .io_bus
1323059ba43SRob Bradford             .insert(
1333059ba43SRob Bradford                 pci_config_io.clone(),
1343059ba43SRob Bradford                 PCI_CONFIG_IO_PORT,
1353059ba43SRob Bradford                 PCI_CONFIG_IO_PORT_SIZE,
1363059ba43SRob Bradford             )
1373059ba43SRob Bradford             .map_err(DeviceManagerError::BusError)?;
1383059ba43SRob Bradford 
1393059ba43SRob Bradford         segment.pci_config_io = Some(pci_config_io);
1403059ba43SRob Bradford 
1413059ba43SRob Bradford         Ok(segment)
1423059ba43SRob Bradford     }
1433059ba43SRob Bradford 
144*c99660a8SRuoqing He     #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
new_default_segment( address_manager: &Arc<AddressManager>, mem32_allocator: Arc<Mutex<AddressAllocator>>, mem64_allocator: Arc<Mutex<AddressAllocator>>, pci_irq_slots: &[u8; 32], ) -> DeviceManagerResult<PciSegment>1453059ba43SRob Bradford     pub(crate) fn new_default_segment(
1463059ba43SRob Bradford         address_manager: &Arc<AddressManager>,
14745b01d59SThomas Barrett         mem32_allocator: Arc<Mutex<AddressAllocator>>,
14845b01d59SThomas Barrett         mem64_allocator: Arc<Mutex<AddressAllocator>>,
149cf1c2bf0SRob Bradford         pci_irq_slots: &[u8; 32],
1503059ba43SRob Bradford     ) -> DeviceManagerResult<PciSegment> {
15145b01d59SThomas Barrett         Self::new(
15245b01d59SThomas Barrett             0,
15345b01d59SThomas Barrett             0,
15445b01d59SThomas Barrett             address_manager,
15545b01d59SThomas Barrett             mem32_allocator,
15645b01d59SThomas Barrett             mem64_allocator,
15745b01d59SThomas Barrett             pci_irq_slots,
15845b01d59SThomas Barrett         )
1593059ba43SRob Bradford     }
1603059ba43SRob Bradford 
next_device_bdf(&self) -> DeviceManagerResult<PciBdf>161ae83e3b3SRob Bradford     pub(crate) fn next_device_bdf(&self) -> DeviceManagerResult<PciBdf> {
162ae83e3b3SRob Bradford         Ok(PciBdf::new(
163ae83e3b3SRob Bradford             self.id,
164ae83e3b3SRob Bradford             0,
165ae83e3b3SRob Bradford             self.pci_bus
16684fc0e09SRob Bradford                 .lock()
16784fc0e09SRob Bradford                 .unwrap()
16884fc0e09SRob Bradford                 .next_device_id()
169ae83e3b3SRob Bradford                 .map_err(DeviceManagerError::NextPciDeviceId)? as u8,
170ae83e3b3SRob Bradford             0,
171ae83e3b3SRob Bradford         ))
17284fc0e09SRob Bradford     }
17384fc0e09SRob Bradford 
reserve_legacy_interrupts_for_pci_devices( address_manager: &Arc<AddressManager>, pci_irq_slots: &mut [u8; 32], ) -> DeviceManagerResult<()>174cf1c2bf0SRob Bradford     pub fn reserve_legacy_interrupts_for_pci_devices(
17584fc0e09SRob Bradford         address_manager: &Arc<AddressManager>,
176cf1c2bf0SRob Bradford         pci_irq_slots: &mut [u8; 32],
17784fc0e09SRob Bradford     ) -> DeviceManagerResult<()> {
17884fc0e09SRob Bradford         // Reserve 8 IRQs which will be shared across all PCI devices.
17984fc0e09SRob Bradford         let num_irqs = 8;
18084fc0e09SRob Bradford         let mut irqs: Vec<u8> = Vec::new();
18184fc0e09SRob Bradford         for _ in 0..num_irqs {
18284fc0e09SRob Bradford             irqs.push(
18384fc0e09SRob Bradford                 address_manager
18484fc0e09SRob Bradford                     .allocator
18584fc0e09SRob Bradford                     .lock()
18684fc0e09SRob Bradford                     .unwrap()
18784fc0e09SRob Bradford                     .allocate_irq()
18884fc0e09SRob Bradford                     .ok_or(DeviceManagerError::AllocateIrq)? as u8,
18984fc0e09SRob Bradford             );
19084fc0e09SRob Bradford         }
19184fc0e09SRob Bradford 
19284fc0e09SRob Bradford         // There are 32 devices on the PCI bus, let's assign them an IRQ.
19384fc0e09SRob Bradford         for i in 0..32 {
194b71564f2SBo Chen             pci_irq_slots[i] = irqs[i % num_irqs];
19584fc0e09SRob Bradford         }
19684fc0e09SRob Bradford 
19784fc0e09SRob Bradford         Ok(())
19884fc0e09SRob Bradford     }
19984fc0e09SRob Bradford }
2008b67298aSRob Bradford 
2018b67298aSRob Bradford struct PciDevSlot {
2028b67298aSRob Bradford     device_id: u8,
2038b67298aSRob Bradford }
2048b67298aSRob Bradford 
2058b67298aSRob Bradford impl Aml for PciDevSlot {
to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink)20673c41567SRob Bradford     fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
2078b67298aSRob Bradford         let sun = self.device_id;
2088b67298aSRob Bradford         let adr: u32 = (self.device_id as u32) << 16;
2098b67298aSRob Bradford         aml::Device::new(
2108b67298aSRob Bradford             format!("S{:03}", self.device_id).as_str().into(),
2118b67298aSRob Bradford             vec![
2128b67298aSRob Bradford                 &aml::Name::new("_SUN".into(), &sun),
2138b67298aSRob Bradford                 &aml::Name::new("_ADR".into(), &adr),
2148b67298aSRob Bradford                 &aml::Method::new(
2158b67298aSRob Bradford                     "_EJ0".into(),
2168b67298aSRob Bradford                     1,
2178b67298aSRob Bradford                     true,
2188b67298aSRob Bradford                     vec![&aml::MethodCall::new(
2198b67298aSRob Bradford                         "\\_SB_.PHPR.PCEJ".into(),
2207a4606f8SRob Bradford                         vec![&aml::Path::new("_SUN"), &aml::Path::new("_SEG")],
2218b67298aSRob Bradford                     )],
2228b67298aSRob Bradford                 ),
2238b67298aSRob Bradford             ],
2248b67298aSRob Bradford         )
22573c41567SRob Bradford         .to_aml_bytes(sink)
2268b67298aSRob Bradford     }
2278b67298aSRob Bradford }
2288b67298aSRob Bradford 
2298b67298aSRob Bradford struct PciDevSlotNotify {
2308b67298aSRob Bradford     device_id: u8,
2318b67298aSRob Bradford }
2328b67298aSRob Bradford 
2338b67298aSRob Bradford impl Aml for PciDevSlotNotify {
to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink)23473c41567SRob Bradford     fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
2358b67298aSRob Bradford         let device_id_mask: u32 = 1 << self.device_id;
2368b67298aSRob Bradford         let object = aml::Path::new(&format!("S{:03}", self.device_id));
23773c41567SRob Bradford         aml::And::new(&aml::Local(0), &aml::Arg(0), &device_id_mask).to_aml_bytes(sink);
238e04cbb2aSRob Bradford         aml::If::new(
2398b67298aSRob Bradford             &aml::Equal::new(&aml::Local(0), &device_id_mask),
2408b67298aSRob Bradford             vec![&aml::Notify::new(&object, &aml::Arg(1))],
2418b67298aSRob Bradford         )
24273c41567SRob Bradford         .to_aml_bytes(sink);
2438b67298aSRob Bradford     }
2448b67298aSRob Bradford }
2458b67298aSRob Bradford 
2468b67298aSRob Bradford struct PciDevSlotMethods {}
2478b67298aSRob Bradford 
2488b67298aSRob Bradford impl Aml for PciDevSlotMethods {
to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink)24973c41567SRob Bradford     fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
2508b67298aSRob Bradford         let mut device_notifies = Vec::new();
2518b67298aSRob Bradford         for device_id in 0..32 {
2528b67298aSRob Bradford             device_notifies.push(PciDevSlotNotify { device_id });
2538b67298aSRob Bradford         }
2548b67298aSRob Bradford 
25573c41567SRob Bradford         let mut device_notifies_refs: Vec<&dyn Aml> = Vec::new();
2568b67298aSRob Bradford         for device_notify in device_notifies.iter() {
2578b67298aSRob Bradford             device_notifies_refs.push(device_notify);
2588b67298aSRob Bradford         }
2598b67298aSRob Bradford 
26073c41567SRob Bradford         aml::Method::new("DVNT".into(), 2, true, device_notifies_refs).to_aml_bytes(sink);
261e04cbb2aSRob Bradford         aml::Method::new(
2628b67298aSRob Bradford             "PCNT".into(),
2638b67298aSRob Bradford             0,
2648b67298aSRob Bradford             true,
2658b67298aSRob Bradford             vec![
2667a4606f8SRob Bradford                 &aml::Acquire::new("\\_SB_.PHPR.BLCK".into(), 0xffff),
2677a4606f8SRob Bradford                 &aml::Store::new(&aml::Path::new("\\_SB_.PHPR.PSEG"), &aml::Path::new("_SEG")),
2688b67298aSRob Bradford                 &aml::MethodCall::new(
2698b67298aSRob Bradford                     "DVNT".into(),
2708b67298aSRob Bradford                     vec![&aml::Path::new("\\_SB_.PHPR.PCIU"), &aml::ONE],
2718b67298aSRob Bradford                 ),
2728b67298aSRob Bradford                 &aml::MethodCall::new(
2738b67298aSRob Bradford                     "DVNT".into(),
2748b67298aSRob Bradford                     vec![&aml::Path::new("\\_SB_.PHPR.PCID"), &3usize],
2758b67298aSRob Bradford                 ),
2767a4606f8SRob Bradford                 &aml::Release::new("\\_SB_.PHPR.BLCK".into()),
2778b67298aSRob Bradford             ],
2788b67298aSRob Bradford         )
27973c41567SRob Bradford         .to_aml_bytes(sink)
2808b67298aSRob Bradford     }
2818b67298aSRob Bradford }
2828b67298aSRob Bradford 
2838b67298aSRob Bradford struct PciDsmMethod {}
2848b67298aSRob Bradford 
2858b67298aSRob Bradford impl Aml for PciDsmMethod {
to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink)28673c41567SRob Bradford     fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
2878b67298aSRob Bradford         // Refer to ACPI spec v6.3 Ch 9.1.1 and PCI Firmware spec v3.3 Ch 4.6.1
2888b67298aSRob Bradford         // _DSM (Device Specific Method), the following is the implementation in ASL.
2898b67298aSRob Bradford         /*
2908b67298aSRob Bradford         Method (_DSM, 4, NotSerialized)  // _DSM: Device-Specific Method
2918b67298aSRob Bradford         {
2928b67298aSRob Bradford               If ((Arg0 == ToUUID ("e5c937d0-3553-4d7a-9117-ea4d19c3434d") /* Device Labeling Interface */))
2938b67298aSRob Bradford               {
2948b67298aSRob Bradford                   If ((Arg2 == Zero))
2958b67298aSRob Bradford                   {
2968b67298aSRob Bradford                       Return (Buffer (One) { 0x21 })
2978b67298aSRob Bradford                   }
2988b67298aSRob Bradford                   If ((Arg2 == 0x05))
2998b67298aSRob Bradford                   {
3008b67298aSRob Bradford                       Return (Zero)
3018b67298aSRob Bradford                   }
3028b67298aSRob Bradford               }
3038b67298aSRob Bradford 
3048b67298aSRob Bradford               Return (Buffer (One) { 0x00 })
3058b67298aSRob Bradford         }
3068b67298aSRob Bradford          */
3078b67298aSRob Bradford         /*
3088b67298aSRob Bradford          * As per ACPI v6.3 Ch 19.6.142, the UUID is required to be in mixed endian:
3098b67298aSRob Bradford          * Among the fields of a UUID:
3108b67298aSRob Bradford          *   {d1 (8 digits)} - {d2 (4 digits)} - {d3 (4 digits)} - {d4 (16 digits)}
3118b67298aSRob Bradford          * d1 ~ d3 need to be little endian, d4 be big endian.
3128b67298aSRob Bradford          * See https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding .
3138b67298aSRob Bradford          */
3148b67298aSRob Bradford         let uuid = Uuid::parse_str("E5C937D0-3553-4D7A-9117-EA4D19C3434D").unwrap();
3158b67298aSRob Bradford         let (uuid_d1, uuid_d2, uuid_d3, uuid_d4) = uuid.as_fields();
3168b67298aSRob Bradford         let mut uuid_buf = vec![];
317f32487f8SRob Bradford         uuid_buf.extend(uuid_d1.to_le_bytes());
318f32487f8SRob Bradford         uuid_buf.extend(uuid_d2.to_le_bytes());
319f32487f8SRob Bradford         uuid_buf.extend(uuid_d3.to_le_bytes());
3208b67298aSRob Bradford         uuid_buf.extend(uuid_d4);
3218b67298aSRob Bradford         aml::Method::new(
3228b67298aSRob Bradford             "_DSM".into(),
3238b67298aSRob Bradford             4,
3248b67298aSRob Bradford             false,
3258b67298aSRob Bradford             vec![
3268b67298aSRob Bradford                 &aml::If::new(
32773c41567SRob Bradford                     &aml::Equal::new(&aml::Arg(0), &aml::BufferData::new(uuid_buf)),
3288b67298aSRob Bradford                     vec![
3298b67298aSRob Bradford                         &aml::If::new(
3308b67298aSRob Bradford                             &aml::Equal::new(&aml::Arg(2), &aml::ZERO),
33173c41567SRob Bradford                             vec![&aml::Return::new(&aml::BufferData::new(vec![0x21]))],
3328b67298aSRob Bradford                         ),
3338b67298aSRob Bradford                         &aml::If::new(
3348b67298aSRob Bradford                             &aml::Equal::new(&aml::Arg(2), &0x05u8),
3358b67298aSRob Bradford                             vec![&aml::Return::new(&aml::ZERO)],
3368b67298aSRob Bradford                         ),
3378b67298aSRob Bradford                     ],
3388b67298aSRob Bradford                 ),
33973c41567SRob Bradford                 &aml::Return::new(&aml::BufferData::new(vec![0])),
3408b67298aSRob Bradford             ],
3418b67298aSRob Bradford         )
34273c41567SRob Bradford         .to_aml_bytes(sink)
3438b67298aSRob Bradford     }
3448b67298aSRob Bradford }
3458b67298aSRob Bradford 
3468b67298aSRob Bradford impl Aml for PciSegment {
to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink)34773c41567SRob Bradford     fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) {
34873c41567SRob Bradford         let mut pci_dsdt_inner_data: Vec<&dyn Aml> = Vec::new();
34973c41567SRob Bradford         let hid = aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A08"));
3508b67298aSRob Bradford         pci_dsdt_inner_data.push(&hid);
35173c41567SRob Bradford         let cid = aml::Name::new("_CID".into(), &aml::EISAName::new("PNP0A03"));
3528b67298aSRob Bradford         pci_dsdt_inner_data.push(&cid);
3538b67298aSRob Bradford         let adr = aml::Name::new("_ADR".into(), &aml::ZERO);
3548b67298aSRob Bradford         pci_dsdt_inner_data.push(&adr);
355b59f1d90SRob Bradford         let seg = aml::Name::new("_SEG".into(), &self.id);
3568b67298aSRob Bradford         pci_dsdt_inner_data.push(&seg);
3578b67298aSRob Bradford         let uid = aml::Name::new("_UID".into(), &aml::ZERO);
3588b67298aSRob Bradford         pci_dsdt_inner_data.push(&uid);
3598b67298aSRob Bradford         let cca = aml::Name::new("_CCA".into(), &aml::ONE);
3608b67298aSRob Bradford         pci_dsdt_inner_data.push(&cca);
3618b67298aSRob Bradford         let supp = aml::Name::new("SUPP".into(), &aml::ZERO);
3628b67298aSRob Bradford         pci_dsdt_inner_data.push(&supp);
3638b67298aSRob Bradford 
3643029fbeaSThomas Barrett         let proximity_domain = self.proximity_domain;
3658b67298aSRob Bradford         let pxm_return = aml::Return::new(&proximity_domain);
3668b67298aSRob Bradford         let pxm = aml::Method::new("_PXM".into(), 0, false, vec![&pxm_return]);
3678b67298aSRob Bradford         pci_dsdt_inner_data.push(&pxm);
3688b67298aSRob Bradford 
3698b67298aSRob Bradford         let pci_dsm = PciDsmMethod {};
3708b67298aSRob Bradford         pci_dsdt_inner_data.push(&pci_dsm);
3718b67298aSRob Bradford 
37245b01d59SThomas Barrett         #[allow(clippy::if_same_then_else)]
373c118d7d7SRob Bradford         let crs = if self.id == 0 {
374c118d7d7SRob Bradford             aml::Name::new(
3758b67298aSRob Bradford                 "_CRS".into(),
3768b67298aSRob Bradford                 &aml::ResourceTemplate::new(vec![
3778b67298aSRob Bradford                     &aml::AddressSpace::new_bus_number(0x0u16, 0x0u16),
3788b67298aSRob Bradford                     #[cfg(target_arch = "x86_64")]
37973c41567SRob Bradford                     &aml::IO::new(0xcf8, 0xcf8, 1, 0x8),
38045b01d59SThomas Barrett                     &aml::Memory32Fixed::new(
38145b01d59SThomas Barrett                         true,
38245b01d59SThomas Barrett                         self.mmio_config_address as u32,
38345b01d59SThomas Barrett                         layout::PCI_MMIO_CONFIG_SIZE_PER_SEGMENT as u32,
38445b01d59SThomas Barrett                     ),
3858b67298aSRob Bradford                     &aml::AddressSpace::new_memory(
3864548de19SRob Bradford                         aml::AddressSpaceCacheable::NotCacheable,
3878b67298aSRob Bradford                         true,
38845b01d59SThomas Barrett                         self.start_of_mem32_area,
38945b01d59SThomas Barrett                         self.end_of_mem32_area,
390f485922bSRob Bradford                         None,
3918b67298aSRob Bradford                     ),
3928b67298aSRob Bradford                     &aml::AddressSpace::new_memory(
3934548de19SRob Bradford                         aml::AddressSpaceCacheable::NotCacheable,
3948b67298aSRob Bradford                         true,
39545b01d59SThomas Barrett                         self.start_of_mem64_area,
39645b01d59SThomas Barrett                         self.end_of_mem64_area,
397f485922bSRob Bradford                         None,
3988b67298aSRob Bradford                     ),
3998b67298aSRob Bradford                     #[cfg(target_arch = "x86_64")]
400f485922bSRob Bradford                     &aml::AddressSpace::new_io(0u16, 0x0cf7u16, None),
4018b67298aSRob Bradford                     #[cfg(target_arch = "x86_64")]
402f485922bSRob Bradford                     &aml::AddressSpace::new_io(0x0d00u16, 0xffffu16, None),
4038b67298aSRob Bradford                 ]),
404c118d7d7SRob Bradford             )
405c118d7d7SRob Bradford         } else {
406c118d7d7SRob Bradford             aml::Name::new(
407c118d7d7SRob Bradford                 "_CRS".into(),
408c118d7d7SRob Bradford                 &aml::ResourceTemplate::new(vec![
409c118d7d7SRob Bradford                     &aml::AddressSpace::new_bus_number(0x0u16, 0x0u16),
410c118d7d7SRob Bradford                     &aml::Memory32Fixed::new(
411c118d7d7SRob Bradford                         true,
412c118d7d7SRob Bradford                         self.mmio_config_address as u32,
4132f8540daSHenry Wang                         layout::PCI_MMIO_CONFIG_SIZE_PER_SEGMENT as u32,
414c118d7d7SRob Bradford                     ),
415c118d7d7SRob Bradford                     &aml::AddressSpace::new_memory(
4164548de19SRob Bradford                         aml::AddressSpaceCacheable::NotCacheable,
417c118d7d7SRob Bradford                         true,
41845b01d59SThomas Barrett                         self.start_of_mem32_area,
41945b01d59SThomas Barrett                         self.end_of_mem32_area,
42045b01d59SThomas Barrett                         None,
42145b01d59SThomas Barrett                     ),
42245b01d59SThomas Barrett                     &aml::AddressSpace::new_memory(
42345b01d59SThomas Barrett                         aml::AddressSpaceCacheable::NotCacheable,
42445b01d59SThomas Barrett                         true,
42545b01d59SThomas Barrett                         self.start_of_mem64_area,
42645b01d59SThomas Barrett                         self.end_of_mem64_area,
427f485922bSRob Bradford                         None,
428c118d7d7SRob Bradford                     ),
429c118d7d7SRob Bradford                 ]),
430c118d7d7SRob Bradford             )
431c118d7d7SRob Bradford         };
4328b67298aSRob Bradford         pci_dsdt_inner_data.push(&crs);
4338b67298aSRob Bradford 
4348b67298aSRob Bradford         let mut pci_devices = Vec::new();
4358b67298aSRob Bradford         for device_id in 0..32 {
4368b67298aSRob Bradford             let pci_device = PciDevSlot { device_id };
4378b67298aSRob Bradford             pci_devices.push(pci_device);
4388b67298aSRob Bradford         }
4398b67298aSRob Bradford         for pci_device in pci_devices.iter() {
4408b67298aSRob Bradford             pci_dsdt_inner_data.push(pci_device);
4418b67298aSRob Bradford         }
4428b67298aSRob Bradford 
4438b67298aSRob Bradford         let pci_device_methods = PciDevSlotMethods {};
4448b67298aSRob Bradford         pci_dsdt_inner_data.push(&pci_device_methods);
4458b67298aSRob Bradford 
4468b67298aSRob Bradford         // Build PCI routing table, listing IRQs assigned to PCI devices.
4478b67298aSRob Bradford         let prt_package_list: Vec<(u32, u32)> = self
4488b67298aSRob Bradford             .pci_irq_slots
4498b67298aSRob Bradford             .iter()
4508b67298aSRob Bradford             .enumerate()
4518b67298aSRob Bradford             .map(|(i, irq)| (((((i as u32) & 0x1fu32) << 16) | 0xffffu32), *irq as u32))
4528b67298aSRob Bradford             .collect();
4538b67298aSRob Bradford         let prt_package_list: Vec<aml::Package> = prt_package_list
4548b67298aSRob Bradford             .iter()
4558b67298aSRob Bradford             .map(|(bdf, irq)| aml::Package::new(vec![bdf, &0u8, &0u8, irq]))
4568b67298aSRob Bradford             .collect();
4578b67298aSRob Bradford         let prt_package_list: Vec<&dyn Aml> = prt_package_list
4588b67298aSRob Bradford             .iter()
4598b67298aSRob Bradford             .map(|item| item as &dyn Aml)
4608b67298aSRob Bradford             .collect();
4618b67298aSRob Bradford         let prt = aml::Name::new("_PRT".into(), &aml::Package::new(prt_package_list));
4628b67298aSRob Bradford         pci_dsdt_inner_data.push(&prt);
4638b67298aSRob Bradford 
464a7fba810SRob Bradford         aml::Device::new(
465ba1e8913SWei Liu             format!("_SB_.PC{:02X}", self.id).as_str().into(),
466a7fba810SRob Bradford             pci_dsdt_inner_data,
467a7fba810SRob Bradford         )
46873c41567SRob Bradford         .to_aml_bytes(sink)
4698b67298aSRob Bradford     }
4708b67298aSRob Bradford }
471