arch: aarch64: Add PCIe node in FDT for AArch64

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
This commit is contained in:
Michael Zhao
2020-06-03 16:30:33 +08:00
committed by Rob Bradford
parent 598bcf1459
commit f2e484750a
4 changed files with 104 additions and 16 deletions
+53 -2
View File
@@ -17,7 +17,10 @@ use super::super::DeviceType;
use super::super::InitramfsConfig;
use super::get_fdt_addr;
use super::gic::GICDevice;
use super::layout::FDT_MAX_SIZE;
use super::layout::{
FDT_MAX_SIZE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, PCI_MMCONFIG_SIZE,
PCI_MMCONFIG_START,
};
use crate::aarch64::fdt::Error::CstringFDTTransform;
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap};
@@ -94,6 +97,7 @@ pub fn create_fdt<T: DeviceInfoForFDT + Clone + Debug>(
device_info: &HashMap<(DeviceType, String), T>,
gic_device: &Box<dyn GICDevice>,
initrd: &Option<InitramfsConfig>,
pci_space_address: &Option<(u64, u64)>,
) -> Result<Vec<u8>> {
// Alocate stuff necessary for the holding the blob.
let mut fdt = vec![0; FDT_MAX_SIZE];
@@ -122,6 +126,9 @@ pub fn create_fdt<T: DeviceInfoForFDT + Clone + Debug>(
create_clock_node(&mut fdt)?;
create_psci_node(&mut fdt)?;
create_devices_node(&mut fdt, device_info)?;
if let Some((pci_device_base, pci_device_size)) = pci_space_address {
create_pci_nodes(&mut fdt, *pci_device_base, *pci_device_size)?;
}
// End Header node.
append_end_node(&mut fdt)?;
@@ -540,6 +547,49 @@ fn create_devices_node<T: DeviceInfoForFDT + Clone + Debug>(
Ok(())
}
fn create_pci_nodes(fdt: &mut Vec<u8>, pci_device_base: u64, pci_device_size: u64) -> Result<()> {
// Add node for PCIe controller.
// See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel
// and https://elinux.org/Device_Tree_Usage.
let ranges = generate_prop32(&[
// mmio addresses
0x2000000, // (ss = 10: 32-bit memory space)
(MEM_32BIT_DEVICES_START.0 >> 32) as u32, // PCI address
MEM_32BIT_DEVICES_START.0 as u32,
(MEM_32BIT_DEVICES_START.0 >> 32) as u32, // CPU address
MEM_32BIT_DEVICES_START.0 as u32,
(MEM_32BIT_DEVICES_SIZE >> 32) as u32, // size
MEM_32BIT_DEVICES_SIZE as u32,
// device addresses
0x3000000, // (ss = 11: 64-bit memory space)
(pci_device_base >> 32) as u32, // PCI address
pci_device_base as u32,
(pci_device_base >> 32) as u32, // CPU address
pci_device_base as u32,
(pci_device_size >> 32) as u32, // size
pci_device_size as u32,
]);
let bus_range = generate_prop32(&[0, 0]); // Only bus 0
let reg = generate_prop64(&[PCI_MMCONFIG_START.0, PCI_MMCONFIG_SIZE]);
append_begin_node(fdt, "pci")?;
append_property_string(fdt, "compatible", "pci-host-ecam-generic")?;
append_property_string(fdt, "device_type", "pci")?;
append_property(fdt, "ranges", &ranges)?;
append_property(fdt, "bus-range", &bus_range)?;
append_property_u32(fdt, "#address-cells", 3)?;
append_property_u32(fdt, "#size-cells", 2)?;
append_property(fdt, "reg", &reg)?;
append_property_u32(fdt, "#interrupt-cells", 1)?;
append_property_null(fdt, "interrupt-map")?;
append_property_null(fdt, "interrupt-map-mask")?;
append_property_null(fdt, "dma-coherent")?;
append_property_u32(fdt, "msi-parent", MSI_PHANDLE)?;
append_end_node(fdt)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
@@ -603,7 +653,7 @@ mod tests {
let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
let vm = hv.create_vm().unwrap();
let gic = create_gic(&vm, 1).unwrap();
let gic = create_gic(&vm, 1, false).unwrap();
assert!(create_fdt(
&mem,
&CString::new("console=tty0").unwrap(),
@@ -611,6 +661,7 @@ mod tests {
&dev_info,
&gic,
&None,
&None,
)
.is_ok())
}