blob: 1d05c18d50d13f9938e235ab5ff47200565d552b [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
Alice Wangeade1672023-06-08 14:56:20 +000017use crate::memory::{MemoryTracker, MemoryTrackerError};
Andrew Walbranb398fc82023-01-24 14:45:46 +000018use alloc::boxed::Box;
Alice Wang287de622023-06-08 13:17:03 +000019use core::fmt;
Alice Wang7c55c7d2023-07-05 14:51:40 +000020use core::marker::PhantomData;
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::{
Alice Wang16e7c3f2023-07-06 08:06:00 +000025 device::{blk, socket},
Alice Wang0e086232023-06-12 13:47:40 +000026 transport::pci::{
27 bus::{BusDeviceIterator, PciRoot},
28 virtio_device_type, PciTransport,
Andrew Walbran848decf2022-12-15 14:39:38 +000029 },
Alice Wang7c55c7d2023-07-05 14:51:40 +000030 Hal,
Andrew Walbran848decf2022-12-15 14:39:38 +000031};
Andrew Walbran19690632022-12-07 16:41:30 +000032
Andrew Walbranb398fc82023-01-24 14:45:46 +000033pub(super) static PCI_INFO: OnceBox<PciInfo> = OnceBox::new();
34
Alice Wang287de622023-06-08 13:17:03 +000035/// PCI errors.
36#[derive(Debug, Clone)]
37pub enum PciError {
38 /// Attempted to initialize the PCI more than once.
39 DuplicateInitialization,
40 /// Failed to map PCI CAM.
41 CamMapFailed(MemoryTrackerError),
42 /// Failed to map PCI BAR.
43 BarMapFailed(MemoryTrackerError),
44}
45
46impl fmt::Display for PciError {
47 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48 match self {
49 Self::DuplicateInitialization => {
50 write!(f, "Attempted to initialize the PCI more than once.")
51 }
52 Self::CamMapFailed(e) => write!(f, "Failed to map PCI CAM: {e}"),
53 Self::BarMapFailed(e) => write!(f, "Failed to map PCI BAR: {e}"),
54 }
55 }
56}
57
Andrew Walbranb398fc82023-01-24 14:45:46 +000058/// Prepares to use VirtIO PCI devices.
59///
60/// In particular:
61///
62/// 1. Maps the PCI CAM and BAR range in the page table and MMIO guard.
63/// 2. Stores the `PciInfo` for the VirtIO HAL to use later.
64/// 3. Creates and returns a `PciRoot`.
65///
66/// This must only be called once; it will panic if it is called a second time.
Alice Wangeff58392023-07-04 13:32:09 +000067pub fn initialize(pci_info: PciInfo, memory: &mut MemoryTracker) -> Result<PciRoot, PciError> {
Alice Wang287de622023-06-08 13:17:03 +000068 PCI_INFO.set(Box::new(pci_info.clone())).map_err(|_| PciError::DuplicateInitialization)?;
Andrew Walbranb398fc82023-01-24 14:45:46 +000069
Alice Wang287de622023-06-08 13:17:03 +000070 memory.map_mmio_range(pci_info.cam_range.clone()).map_err(PciError::CamMapFailed)?;
71 let bar_range = pci_info.bar_range.start as usize..pci_info.bar_range.end as usize;
72 memory.map_mmio_range(bar_range).map_err(PciError::BarMapFailed)?;
Andrew Walbranb398fc82023-01-24 14:45:46 +000073
74 // Safety: This is the only place where we call make_pci_root, and `PCI_INFO.set` above will
75 // panic if it is called a second time.
76 Ok(unsafe { pci_info.make_pci_root() })
77}
78
Alice Wangeade1672023-06-08 14:56:20 +000079/// Virtio Block device.
Alice Wang7c55c7d2023-07-05 14:51:40 +000080pub type VirtIOBlk<T> = blk::VirtIOBlk<T, PciTransport>;
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000081
Alice Wang16e7c3f2023-07-06 08:06:00 +000082/// Virtio Socket device.
83///
84/// Spec: https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html 5.10
85pub type VirtIOSocket<T> = socket::VirtIOSocket<T, PciTransport>;
86
Alice Wang0e086232023-06-12 13:47:40 +000087/// An iterator that iterates over the PCI transport for each device.
Alice Wang7c55c7d2023-07-05 14:51:40 +000088pub struct PciTransportIterator<'a, T: Hal> {
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +000089 pci_root: &'a mut PciRoot,
90 bus: BusDeviceIterator,
Alice Wang7c55c7d2023-07-05 14:51:40 +000091 _hal: PhantomData<T>,
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +000092}
93
Alice Wang7c55c7d2023-07-05 14:51:40 +000094impl<'a, T: Hal> PciTransportIterator<'a, T> {
Alice Wangeade1672023-06-08 14:56:20 +000095 /// Creates a new iterator.
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +000096 pub fn new(pci_root: &'a mut PciRoot) -> Self {
97 let bus = pci_root.enumerate_bus(0);
Alice Wang7c55c7d2023-07-05 14:51:40 +000098 Self { pci_root, bus, _hal: PhantomData }
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +000099 }
100}
101
Alice Wang7c55c7d2023-07-05 14:51:40 +0000102impl<'a, T: Hal> Iterator for PciTransportIterator<'a, T> {
Alice Wang0e086232023-06-12 13:47:40 +0000103 type Item = PciTransport;
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000104
105 fn next(&mut self) -> Option<Self::Item> {
106 loop {
107 let (device_function, info) = self.bus.next()?;
108 let (status, command) = self.pci_root.get_status_command(device_function);
109 debug!(
110 "Found PCI device {} at {}, status {:?} command {:?}",
111 info, device_function, status, command
112 );
113
Pierre-Clément Tosiebb37602023-02-17 14:57:26 +0000114 let Some(virtio_type) = virtio_device_type(&info) else {
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000115 continue;
116 };
Andrew Walbrand1d03182022-12-09 18:20:01 +0000117 debug!(" VirtIO {:?}", virtio_type);
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000118
Alice Wang7c55c7d2023-07-05 14:51:40 +0000119 return PciTransport::new::<T>(self.pci_root, device_function).ok();
Andrew Walbrand1d03182022-12-09 18:20:01 +0000120 }
121 }
Pierre-Clément Tosie8ec0392023-01-16 15:38:31 +0000122}