blob: 7baabed80be787fb37421c264110db848d0c5c60 [file] [log] [blame]
Andrew Walbran19690632022-12-07 16:41:30 +00001// Copyright 2022, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Functions to scan the PCI bus for VirtIO device and allocate BARs.
16
17use crate::{entry::RebootReason, memory::MemoryTracker};
18use core::ffi::CStr;
19use libfdt::{Fdt, FdtNode};
20use log::{debug, error};
21
22/// PCI MMIO configuration region size.
23const PCI_CFG_SIZE: usize = 0x100_0000;
24
25/// Finds an FDT node with compatible=pci-host-cam-generic.
26pub fn pci_node(fdt: &Fdt) -> Result<FdtNode, RebootReason> {
27 fdt.compatible_nodes(CStr::from_bytes_with_nul(b"pci-host-cam-generic\0").unwrap())
28 .map_err(|e| {
29 error!("Failed to find PCI bus in FDT: {}", e);
30 RebootReason::InvalidFdt
31 })?
32 .next()
33 .ok_or(RebootReason::InvalidFdt)
34}
35
36pub fn map_cam(pci_node: &FdtNode, memory: &mut MemoryTracker) -> Result<(), RebootReason> {
37 // Parse reg property to find CAM.
38 let pci_reg = pci_node
39 .reg()
40 .map_err(|e| {
41 error!("Error getting reg property from PCI node: {}", e);
42 RebootReason::InvalidFdt
43 })?
44 .ok_or_else(|| {
45 error!("PCI node missing reg property.");
46 RebootReason::InvalidFdt
47 })?
48 .next()
49 .ok_or_else(|| {
50 error!("Empty reg property on PCI node.");
51 RebootReason::InvalidFdt
52 })?;
53 let cam_addr = pci_reg.addr as usize;
54 let cam_size = pci_reg.size.ok_or_else(|| {
55 error!("PCI reg property missing size.");
56 RebootReason::InvalidFdt
57 })? as usize;
58 debug!("Found PCI CAM at {:#x}-{:#x}", cam_addr, cam_addr + cam_size);
59 // Check that the CAM is the size we expect, so we don't later try accessing it beyond its
60 // bounds. If it is a different size then something is very wrong and we shouldn't continue to
61 // access it; maybe there is some new version of PCI we don't know about.
62 if cam_size != PCI_CFG_SIZE {
63 error!("FDT says PCI CAM is {} bytes but we expected {}.", cam_size, PCI_CFG_SIZE);
64 return Err(RebootReason::InvalidFdt);
65 }
66
67 // Map the CAM as MMIO.
68 memory.map_mmio_range(cam_addr..cam_addr + cam_size).map_err(|e| {
69 error!("Failed to map PCI CAM: {}", e);
70 RebootReason::InternalError
71 })?;
72
73 Ok(())
74}