From 2da98eaaa8e07639f3c2538c4180ec1f66887124 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 10 Dec 2023 21:25:54 +0200 Subject: [PATCH] dev/pci: make PCI driver an external crate --- Cargo.toml | 3 + driver/bus/pci/Cargo.toml | 16 +++ .../pci => driver/bus/pci/src}/capability.rs | 7 +- .../pci/mod.rs => driver/bus/pci/src/lib.rs | 89 ++++++++++++--- .../pci => driver/bus/pci/src}/space/ecam.rs | 0 .../pci => driver/bus/pci/src}/space/mod.rs | 3 +- src/arch/x86_64/mod.rs | 13 ++- src/device/bus/mod.rs | 2 - src/device/nvme/mod.rs | 102 +++++++++--------- 9 files changed, 158 insertions(+), 77 deletions(-) create mode 100644 driver/bus/pci/Cargo.toml rename {src/device/bus/pci => driver/bus/pci/src}/capability.rs (95%) rename src/device/bus/pci/mod.rs => driver/bus/pci/src/lib.rs (79%) rename {src/device/bus/pci => driver/bus/pci/src}/space/ecam.rs (100%) rename {src/device/bus/pci => driver/bus/pci/src}/space/mod.rs (99%) diff --git a/Cargo.toml b/Cargo.toml index bbb1ec79..cfb3d84b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,9 @@ memtables = { path = "lib/memtables" } vmalloc = { path = "lib/vmalloc" } device-api-macros = { path = "lib/device-api/macros" } +# Drivers +ygg_driver_pci = { path = "driver/bus/pci" } + atomic_enum = "0.2.0" bitflags = "2.3.3" linked_list_allocator = "0.10.5" diff --git a/driver/bus/pci/Cargo.toml b/driver/bus/pci/Cargo.toml new file mode 100644 index 00000000..5268dc89 --- /dev/null +++ b/driver/bus/pci/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "ygg_driver_pci" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" } +device-api = { path = "../../../lib/device-api", features = ["derive"] } +kernel-util = { path = "../../../lib/kernel-util" } + +log = "0.4.20" +bitflags = "2.3.3" + +acpi = { git = "https://github.com/alnyan/acpi.git", package = "acpi", branch = "acpi-system" } diff --git a/src/device/bus/pci/capability.rs b/driver/bus/pci/src/capability.rs similarity index 95% rename from src/device/bus/pci/capability.rs rename to driver/bus/pci/src/capability.rs index d9e71baa..ddd324bd 100644 --- a/src/device/bus/pci/capability.rs +++ b/driver/bus/pci/src/capability.rs @@ -1,15 +1,14 @@ //! PCI capability structures and queries -use abi::error::Error; use device_api::interrupt::{MessageInterruptController, MsiHandler}; use kernel_util::mem::{ address::{FromRaw, PhysicalAddress}, device::DeviceMemoryIoMut, }; - -use crate::device::bus::pci::PciBaseAddress; +use yggdrasil_abi::error::Error; use super::{PciCapability, PciCapabilityId, PciConfigurationSpace}; +use crate::PciBaseAddress; /// MSI-X capability query pub struct MsiXCapability; @@ -61,7 +60,7 @@ impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiXData<'s, S> { return Err(Error::InvalidOperation); }; - debugln!("MSI-X table address: {:#x}", base + table_offset); + log::debug!("MSI-X table address: {:#x}", base + table_offset); unsafe { DeviceMemoryIoMut::map_slice(PhysicalAddress::from_raw(base + table_offset), table_size) diff --git a/src/device/bus/pci/mod.rs b/driver/bus/pci/src/lib.rs similarity index 79% rename from src/device/bus/pci/mod.rs rename to driver/bus/pci/src/lib.rs index 360589d8..b2ae181e 100644 --- a/src/device/bus/pci/mod.rs +++ b/driver/bus/pci/src/lib.rs @@ -1,8 +1,12 @@ //! PCI/PCIe bus interfaces +#![no_std] + +extern crate alloc; + use core::fmt; -use acpi_lib::mcfg::McfgEntry; -use alloc::{boxed::Box, rc::Rc, vec::Vec}; +use acpi::mcfg::McfgEntry; +use alloc::{rc::Rc, vec::Vec}; use bitflags::bitflags; use device_api::Device; use kernel_util::{ @@ -18,8 +22,6 @@ pub use space::{ ecam::PciEcam, PciConfigSpace, PciConfigurationSpace, PciLegacyConfigurationSpace, }; -use crate::device::nvme; - bitflags! { /// Command register of the PCI configuration space pub struct PciCommandRegister: u16 { @@ -100,10 +102,15 @@ pub struct PciDeviceInfo { pub config_space: PciConfigSpace, } -/// Interface for "taking" PCI devices from the bus -pub trait FromPciBus: Sized { - /// Constructs an instance of a driver for the device using the information provided - fn from_pci_bus(info: &PciDeviceInfo) -> Result; +pub enum PciMatch { + Generic(fn(&PciDeviceInfo) -> bool), + Class(u8, Option, Option), +} + +pub struct PciDriver { + name: &'static str, + check: PciMatch, + probe: fn(&PciDeviceInfo) -> Result<&'static dyn Device, Error>, } /// Used to store PCI bus devices which were enumerated by the kernel @@ -296,28 +303,76 @@ fn setup_bus_device(device: &mut PciBusDevice) -> Result<(), Error> { let config = &device.info.config_space; - debugln!( + log::debug!( "{}: {:04x}:{:04x}", device.info.address, config.vendor_id(), config.device_id() ); - // Match by class - match (config.class_code(), config.subclass(), config.prog_if()) { - (0x01, 0x08, 0x02) => { - let dev = Box::leak(Box::new(nvme::NvmeController::from_pci_bus(&device.info)?)); + let class = config.class_code(); + let subclass = config.subclass(); + let prog_if = config.prog_if(); + + let drivers = PCI_DRIVERS.lock(); + for driver in drivers.iter() { + if driver + .check + .check_device(&device.info, class, subclass, prog_if) + { + // TODO add the device to the bus + log::debug!(" -> {:?}", driver.name); + let device = (driver.probe)(&device.info)?; unsafe { - dev.init()?; + device.init()?; } - } - _ => { - debugln!(" -> No driver"); + } else { + log::debug!(" -> No driver"); } } Ok(()) } +impl PciMatch { + pub fn check_device(&self, info: &PciDeviceInfo, class: u8, subclass: u8, prog_if: u8) -> bool { + match self { + Self::Generic(f) => f(info), + &Self::Class(class_, Some(subclass_), Some(prog_if_)) => { + class_ == class && subclass_ == subclass && prog_if_ == prog_if + } + &Self::Class(class_, Some(subclass_), _) => class_ == class && subclass_ == subclass, + &Self::Class(class_, _, _) => class_ == class, + } + } +} + +pub fn register_class_driver( + name: &'static str, + class: u8, + subclass: Option, + prog_if: Option, + probe: fn(&PciDeviceInfo) -> Result<&'static dyn Device, Error>, +) { + PCI_DRIVERS.lock().push(PciDriver { + name, + check: PciMatch::Class(class, subclass, prog_if), + probe, + }); +} + +pub fn register_generic_driver( + name: &'static str, + check: fn(&PciDeviceInfo) -> bool, + probe: fn(&PciDeviceInfo) -> Result<&'static dyn Device, Error>, +) { + PCI_DRIVERS.lock().push(PciDriver { + name, + check: PciMatch::Generic(check), + probe, + }); +} + +static PCI_DRIVERS: IrqSafeSpinlock> = IrqSafeSpinlock::new(Vec::new()); static PCI_MANAGER: IrqSafeSpinlock = IrqSafeSpinlock::new(PciBusManager::new()); diff --git a/src/device/bus/pci/space/ecam.rs b/driver/bus/pci/src/space/ecam.rs similarity index 100% rename from src/device/bus/pci/space/ecam.rs rename to driver/bus/pci/src/space/ecam.rs diff --git a/src/device/bus/pci/space/mod.rs b/driver/bus/pci/src/space/mod.rs similarity index 99% rename from src/device/bus/pci/space/mod.rs rename to driver/bus/pci/src/space/mod.rs index 51773391..182f911f 100644 --- a/src/device/bus/pci/space/mod.rs +++ b/driver/bus/pci/src/space/mod.rs @@ -1,6 +1,5 @@ -use crate::device::bus::pci::PciStatusRegister; - use super::{PciAddress, PciBaseAddress, PciCapability, PciCapabilityId, PciEcam}; +use crate::PciStatusRegister; pub(super) mod ecam; diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index 6c2d474f..5834257c 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -21,6 +21,7 @@ use kernel_util::{ util::OneTimeInit, }; use yboot_proto::{v1::AvailableMemoryRegion, LoadProtocolV1}; +use ygg_driver_pci::PciBusManager; mod acpi; mod apic; @@ -49,8 +50,8 @@ use crate::{ debug::{self, LogLevel}, device::{ self, - bus::pci::PciBusManager, display::{console, fb_console::FramebufferConsole, linear_fb::LinearFramebuffer}, + nvme, tty::CombinedTerminal, }, fs::{ @@ -384,6 +385,16 @@ impl X86_64 { Cpu::init_local(LocalApic::new(), cpu_id as _); if cpu_id == 0 { + // Register the PCI drivers + // TODO make this implicit init + ygg_driver_pci::register_class_driver( + "NVMe Host Controller", + 0x01, + Some(0x08), + Some(0x02), + nvme::probe, + ); + match self.boot_data.get() { &BootData::YBoot(data) => { let start = PhysicalAddress::from_raw(data.initrd_address); diff --git a/src/device/bus/mod.rs b/src/device/bus/mod.rs index e6810506..42007f9c 100644 --- a/src/device/bus/mod.rs +++ b/src/device/bus/mod.rs @@ -2,5 +2,3 @@ #[cfg(feature = "device-tree")] pub mod simple_bus; - -pub mod pci; diff --git a/src/device/nvme/mod.rs b/src/device/nvme/mod.rs index fa705501..0e0ac415 100644 --- a/src/device/nvme/mod.rs +++ b/src/device/nvme/mod.rs @@ -2,7 +2,7 @@ use core::{mem::size_of, time::Duration}; use abi::error::Error; -use alloc::{collections::BTreeMap, vec::Vec}; +use alloc::{boxed::Box, collections::BTreeMap, vec::Vec}; use device_api::{interrupt::MsiHandler, Device}; use kernel_util::{ mem::{ @@ -17,20 +17,19 @@ use tock_registers::{ register_bitfields, register_structs, registers::{ReadOnly, ReadWrite, WriteOnly}, }; +use ygg_driver_pci::{ + capability::{MsiXCapability, MsiXEntry}, + PciBaseAddress, PciCommandRegister, PciConfigurationSpace, PciDeviceInfo, +}; use crate::{ arch::{Architecture, ARCHITECTURE}, - device::{ - bus::pci::{ - capability::MsiXCapability, PciBaseAddress, PciCommandRegister, PciConfigurationSpace, - }, - nvme::{ - command::{ - IdentifyActiveNamespaceIdListRequest, IdentifyControllerRequest, IoRead, IoWrite, - }, - drive::NvmeDrive, - queue::{CompletionQueueEntry, SubmissionQueueEntry}, + device::nvme::{ + command::{ + IdentifyActiveNamespaceIdListRequest, IdentifyControllerRequest, IoRead, IoWrite, }, + drive::NvmeDrive, + queue::{CompletionQueueEntry, SubmissionQueueEntry}, }, task::runtime, }; @@ -41,8 +40,6 @@ use self::{ queue::QueuePair, }; -use super::bus::pci::{capability::MsiXEntry, FromPciBus, PciDeviceInfo}; - mod command; mod drive; mod error; @@ -358,48 +355,51 @@ impl Device for NvmeController { } } -impl FromPciBus for NvmeController { - fn from_pci_bus(info: &PciDeviceInfo) -> Result { - let PciBaseAddress::Memory(bar0) = info.config_space.bar(0).unwrap() else { - panic!(); - }; - - // TODO also support MSI - let mut msix = info.config_space.capability::().unwrap(); - let mut vt = msix.vector_table()?; - - for vector in vt.iter_mut() { - vector.set_masked(true); - } - msix.set_enabled(true); - - let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command()); - cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO); - cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER; - info.config_space.set_command(cmd.bits()); - - let regs = unsafe { DeviceMemoryIo::::map(PhysicalAddress::from_raw(bar0)) }?; - - // Disable the controller - regs.CC.modify(CC::ENABLE::CLEAR); - - let doorbell_shift = regs.CAP.read(CAP::DSTRD) as usize + 1; - - Ok(Self { - regs: IrqSafeSpinlock::new(regs), - admin_q: OneTimeInit::new(), - ioqs: OneTimeInit::new(), - vector_table: IrqSafeSpinlock::new(vt), - drive_table: IrqSafeSpinlock::new(BTreeMap::new()), - controller_id: OneTimeInit::new(), - doorbell_shift, - }) - } -} +// impl FromPciBus for NvmeController { +// fn from_pci_bus(info: &PciDeviceInfo) -> Result { +// } +// } static NVME_CONTROLLERS: IrqSafeSpinlock> = IrqSafeSpinlock::new(Vec::new()); +pub fn probe(info: &PciDeviceInfo) -> Result<&'static dyn Device, Error> { + let PciBaseAddress::Memory(bar0) = info.config_space.bar(0).unwrap() else { + panic!(); + }; + + // TODO also support MSI + let mut msix = info.config_space.capability::().unwrap(); + let mut vt = msix.vector_table()?; + + for vector in vt.iter_mut() { + vector.set_masked(true); + } + msix.set_enabled(true); + + let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command()); + cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO); + cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER; + info.config_space.set_command(cmd.bits()); + + let regs = unsafe { DeviceMemoryIo::::map(PhysicalAddress::from_raw(bar0)) }?; + + // Disable the controller + regs.CC.modify(CC::ENABLE::CLEAR); + + let doorbell_shift = regs.CAP.read(CAP::DSTRD) as usize + 1; + + Ok(Box::leak(Box::new(NvmeController { + regs: IrqSafeSpinlock::new(regs), + admin_q: OneTimeInit::new(), + ioqs: OneTimeInit::new(), + vector_table: IrqSafeSpinlock::new(vt), + drive_table: IrqSafeSpinlock::new(BTreeMap::new()), + controller_id: OneTimeInit::new(), + doorbell_shift, + }))) +} + pub fn register_nvme_controller(ctrl: &'static NvmeController) { let mut list = NVME_CONTROLLERS.lock(); let id = list.len();