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