blob: ad7cfbbecce31256b2f7ce4fe35e6beef56fb14d [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
Andrew Walbran0a8dac72022-12-21 13:49:06 +000015//! Functions to scan the PCI bus for VirtIO devices.
Andrew Walbran19690632022-12-07 16:41:30 +000016
Andrew Walbran848decf2022-12-15 14:39:38 +000017use super::hal::HalImpl;
Alice Wang93ee98a2023-06-08 08:20:39 +000018use crate::entry::RebootReason;
Andrew Walbranb398fc82023-01-24 14:45:46 +000019use alloc::boxed::Box;
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000020use fdtpci::PciInfo;
21use log::{debug, error};
Andrew Walbranb398fc82023-01-24 14:45:46 +000022use once_cell::race::OnceBox;
Andrew Walbran848decf2022-12-15 14:39:38 +000023use virtio_drivers::{
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000024 device::blk,
Andrew Walbran848decf2022-12-15 14:39:38 +000025 transport::{
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +000026 pci::{
27 bus::{BusDeviceIterator, PciRoot},
28 virtio_device_type, PciTransport,
29 },
Andrew Walbran848decf2022-12-15 14:39:38 +000030 DeviceType, Transport,
31 },
32};
Alice Wang93ee98a2023-06-08 08:20:39 +000033use vmbase::memory::MemoryTracker;
Andrew Walbran19690632022-12-07 16:41:30 +000034
Andrew Walbranb398fc82023-01-24 14:45:46 +000035pub(super) static PCI_INFO: OnceBox<PciInfo> = OnceBox::new();
36
37/// Prepares to use VirtIO PCI devices.
38///
39/// In particular:
40///
41/// 1. Maps the PCI CAM and BAR range in the page table and MMIO guard.
42/// 2. Stores the `PciInfo` for the VirtIO HAL to use later.
43/// 3. Creates and returns a `PciRoot`.
44///
45/// This must only be called once; it will panic if it is called a second time.
46pub fn initialise(pci_info: PciInfo, memory: &mut MemoryTracker) -> Result<PciRoot, RebootReason> {
47 map_mmio(&pci_info, memory)?;
48
49 PCI_INFO.set(Box::new(pci_info.clone())).expect("Tried to set PCI_INFO a second time");
50
51 // Safety: This is the only place where we call make_pci_root, and `PCI_INFO.set` above will
52 // panic if it is called a second time.
53 Ok(unsafe { pci_info.make_pci_root() })
54}
55
Andrew Walbran730375d2022-12-21 14:04:34 +000056/// Maps the CAM and BAR range in the page table and MMIO guard.
Andrew Walbranb398fc82023-01-24 14:45:46 +000057fn map_mmio(pci_info: &PciInfo, memory: &mut MemoryTracker) -> Result<(), RebootReason> {
Andrew Walbran730375d2022-12-21 14:04:34 +000058 memory.map_mmio_range(pci_info.cam_range.clone()).map_err(|e| {
59 error!("Failed to map PCI CAM: {}", e);
60 RebootReason::InternalError
61 })?;
Andrew Walbran19690632022-12-07 16:41:30 +000062
Andrew Walbran730375d2022-12-21 14:04:34 +000063 memory
64 .map_mmio_range(pci_info.bar_range.start as usize..pci_info.bar_range.end as usize)
65 .map_err(|e| {
66 error!("Failed to map PCI MMIO range: {}", e);
Andrew Walbran0d8b54d2022-12-08 16:32:33 +000067 RebootReason::InternalError
68 })?;
69
Andrew Walbran730375d2022-12-21 14:04:34 +000070 Ok(())
Andrew Walbran19690632022-12-07 16:41:30 +000071}
Andrew Walbrand1d03182022-12-09 18:20:01 +000072
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000073pub type VirtIOBlk = blk::VirtIOBlk<HalImpl, PciTransport>;
74
75pub struct VirtIOBlkIterator<'a> {
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +000076 pci_root: &'a mut PciRoot,
77 bus: BusDeviceIterator,
78}
79
80impl<'a> VirtIOBlkIterator<'a> {
81 pub fn new(pci_root: &'a mut PciRoot) -> Self {
82 let bus = pci_root.enumerate_bus(0);
83 Self { pci_root, bus }
84 }
85}
86
87impl<'a> Iterator for VirtIOBlkIterator<'a> {
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000088 type Item = VirtIOBlk;
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +000089
90 fn next(&mut self) -> Option<Self::Item> {
91 loop {
92 let (device_function, info) = self.bus.next()?;
93 let (status, command) = self.pci_root.get_status_command(device_function);
94 debug!(
95 "Found PCI device {} at {}, status {:?} command {:?}",
96 info, device_function, status, command
97 );
98
Pierre-Clément Tosiebb37602023-02-17 14:57:26 +000099 let Some(virtio_type) = virtio_device_type(&info) else {
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000100 continue;
101 };
Andrew Walbrand1d03182022-12-09 18:20:01 +0000102 debug!(" VirtIO {:?}", virtio_type);
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000103
104 let mut transport =
105 PciTransport::new::<HalImpl>(self.pci_root, device_function).unwrap();
106 debug!(
Andrew Walbran848decf2022-12-15 14:39:38 +0000107 "Detected virtio PCI device with device type {:?}, features {:#018x}",
108 transport.device_type(),
109 transport.read_device_features(),
110 );
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000111
Andrew Walbran848decf2022-12-15 14:39:38 +0000112 if virtio_type == DeviceType::Block {
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000113 return Some(Self::Item::new(transport).expect("failed to create blk driver"));
Andrew Walbran848decf2022-12-15 14:39:38 +0000114 }
Andrew Walbrand1d03182022-12-09 18:20:01 +0000115 }
116 }
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000117}