blob: b54f7d1b16ea79fb436d3637eac29e7dd8f330df [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 Wangeade1672023-06-08 14:56:20 +000018use crate::memory::{MemoryTracker, MemoryTrackerError};
Andrew Walbranb398fc82023-01-24 14:45:46 +000019use alloc::boxed::Box;
Alice Wang287de622023-06-08 13:17:03 +000020use core::fmt;
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000021use fdtpci::PciInfo;
Alice Wang287de622023-06-08 13:17:03 +000022use log::debug;
Andrew Walbranb398fc82023-01-24 14:45:46 +000023use once_cell::race::OnceBox;
Andrew Walbran848decf2022-12-15 14:39:38 +000024use virtio_drivers::{
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000025 device::blk,
Andrew Walbran848decf2022-12-15 14:39:38 +000026 transport::{
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +000027 pci::{
28 bus::{BusDeviceIterator, PciRoot},
29 virtio_device_type, PciTransport,
30 },
Andrew Walbran848decf2022-12-15 14:39:38 +000031 DeviceType, Transport,
32 },
33};
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
Alice Wang287de622023-06-08 13:17:03 +000037/// PCI errors.
38#[derive(Debug, Clone)]
39pub enum PciError {
40 /// Attempted to initialize the PCI more than once.
41 DuplicateInitialization,
42 /// Failed to map PCI CAM.
43 CamMapFailed(MemoryTrackerError),
44 /// Failed to map PCI BAR.
45 BarMapFailed(MemoryTrackerError),
46}
47
48impl fmt::Display for PciError {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 match self {
51 Self::DuplicateInitialization => {
52 write!(f, "Attempted to initialize the PCI more than once.")
53 }
54 Self::CamMapFailed(e) => write!(f, "Failed to map PCI CAM: {e}"),
55 Self::BarMapFailed(e) => write!(f, "Failed to map PCI BAR: {e}"),
56 }
57 }
58}
59
Andrew Walbranb398fc82023-01-24 14:45:46 +000060/// Prepares to use VirtIO PCI devices.
61///
62/// In particular:
63///
64/// 1. Maps the PCI CAM and BAR range in the page table and MMIO guard.
65/// 2. Stores the `PciInfo` for the VirtIO HAL to use later.
66/// 3. Creates and returns a `PciRoot`.
67///
68/// This must only be called once; it will panic if it is called a second time.
Alice Wang287de622023-06-08 13:17:03 +000069pub fn initialise(pci_info: PciInfo, memory: &mut MemoryTracker) -> Result<PciRoot, PciError> {
70 PCI_INFO.set(Box::new(pci_info.clone())).map_err(|_| PciError::DuplicateInitialization)?;
Andrew Walbranb398fc82023-01-24 14:45:46 +000071
Alice Wang287de622023-06-08 13:17:03 +000072 memory.map_mmio_range(pci_info.cam_range.clone()).map_err(PciError::CamMapFailed)?;
73 let bar_range = pci_info.bar_range.start as usize..pci_info.bar_range.end as usize;
74 memory.map_mmio_range(bar_range).map_err(PciError::BarMapFailed)?;
Andrew Walbranb398fc82023-01-24 14:45:46 +000075
76 // Safety: This is the only place where we call make_pci_root, and `PCI_INFO.set` above will
77 // panic if it is called a second time.
78 Ok(unsafe { pci_info.make_pci_root() })
79}
80
Alice Wangeade1672023-06-08 14:56:20 +000081/// Virtio Block device.
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000082pub type VirtIOBlk = blk::VirtIOBlk<HalImpl, PciTransport>;
83
Alice Wangeade1672023-06-08 14:56:20 +000084/// Virtio Block device iterator.
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000085pub struct VirtIOBlkIterator<'a> {
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +000086 pci_root: &'a mut PciRoot,
87 bus: BusDeviceIterator,
88}
89
90impl<'a> VirtIOBlkIterator<'a> {
Alice Wangeade1672023-06-08 14:56:20 +000091 /// Creates a new iterator.
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +000092 pub fn new(pci_root: &'a mut PciRoot) -> Self {
93 let bus = pci_root.enumerate_bus(0);
94 Self { pci_root, bus }
95 }
96}
97
98impl<'a> Iterator for VirtIOBlkIterator<'a> {
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000099 type Item = VirtIOBlk;
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000100
101 fn next(&mut self) -> Option<Self::Item> {
102 loop {
103 let (device_function, info) = self.bus.next()?;
104 let (status, command) = self.pci_root.get_status_command(device_function);
105 debug!(
106 "Found PCI device {} at {}, status {:?} command {:?}",
107 info, device_function, status, command
108 );
109
Pierre-Clément Tosiebb37602023-02-17 14:57:26 +0000110 let Some(virtio_type) = virtio_device_type(&info) else {
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000111 continue;
112 };
Andrew Walbrand1d03182022-12-09 18:20:01 +0000113 debug!(" VirtIO {:?}", virtio_type);
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000114
115 let mut transport =
116 PciTransport::new::<HalImpl>(self.pci_root, device_function).unwrap();
117 debug!(
Andrew Walbran848decf2022-12-15 14:39:38 +0000118 "Detected virtio PCI device with device type {:?}, features {:#018x}",
119 transport.device_type(),
120 transport.read_device_features(),
121 );
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000122
Andrew Walbran848decf2022-12-15 14:39:38 +0000123 if virtio_type == DeviceType::Block {
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000124 return Some(Self::Item::new(transport).expect("failed to create blk driver"));
Andrew Walbran848decf2022-12-15 14:39:38 +0000125 }
Andrew Walbrand1d03182022-12-09 18:20:01 +0000126 }
127 }
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000128}