pci: move to .init_array-based driver registration
This commit is contained in:
parent
87c7614fd8
commit
d83b82ef45
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2861,6 +2861,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"bitflags 2.8.0",
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"chrono",
|
||||
"crossbeam-queue",
|
||||
"device-api",
|
||||
|
@ -45,6 +45,7 @@ bytemuck.workspace = true
|
||||
futures-util.workspace = true
|
||||
crossbeam-queue.workspace = true
|
||||
async-trait.workspace = true
|
||||
cfg-if.workspace = true
|
||||
|
||||
git-version = "0.3.9"
|
||||
|
||||
|
@ -20,6 +20,7 @@ use regs::{PortRegs, Regs};
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||
use ygg_driver_pci::{
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
PciCommandRegister, PciConfigurationSpace,
|
||||
};
|
||||
use yggdrasil_abi::{error::Error, io::FileMode};
|
||||
@ -191,51 +192,6 @@ impl Device for AhciController {
|
||||
}
|
||||
}
|
||||
|
||||
static SATA_DRIVES: IrqSafeSpinlock<Vec<Arc<AhciPort>>> = IrqSafeSpinlock::new(Vec::new());
|
||||
|
||||
pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
let bar5 = info.config_space.bar(5).ok_or(Error::InvalidOperation)?;
|
||||
let bar5 = bar5.as_memory().ok_or(Error::InvalidOperation)?;
|
||||
|
||||
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());
|
||||
|
||||
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
|
||||
|
||||
// // TODO support regular PCI interrupts (ACPI dependency)
|
||||
// let Some(mut msi) = info.config_space.capability::<MsiCapability>() else {
|
||||
// log::warn!("Ignoring AHCI: does not support MSI (and the OS doesn't yet support PCI IRQ)");
|
||||
// return Err(Error::InvalidOperation);
|
||||
// };
|
||||
|
||||
// Map the registers
|
||||
let regs = unsafe { DeviceMemoryIo::<Regs>::map(bar5, Default::default()) }?;
|
||||
|
||||
let version = Version::try_from(regs.VS.get())?;
|
||||
let ahci_only = regs.CAP.matches_all(CAP::SAM::SET);
|
||||
let max_port_count = regs.CAP.read(CAP::NP) as usize;
|
||||
let has_64_bit = regs.CAP.matches_all(CAP::S64A::SET);
|
||||
|
||||
// TODO extract Number of Command Slots
|
||||
|
||||
let ahci = Arc::new(AhciController {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
ports: OneTimeInit::new(),
|
||||
received_fis_buffers: OneTimeInit::new(),
|
||||
version,
|
||||
max_port_count,
|
||||
ahci_only,
|
||||
has_64_bit,
|
||||
});
|
||||
|
||||
// TODO use multiple vectors if capable
|
||||
info.map_interrupt(InterruptAffinity::Any, ahci.clone())?;
|
||||
|
||||
Ok(ahci)
|
||||
}
|
||||
|
||||
pub fn register_sata_drive(drive: Arc<AhciPort>, probe: bool) {
|
||||
let index = {
|
||||
let mut drives = SATA_DRIVES.lock();
|
||||
@ -273,3 +229,57 @@ pub fn register_sata_drive(drive: Arc<AhciPort>, probe: bool) {
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
static SATA_DRIVES: IrqSafeSpinlock<Vec<Arc<AhciPort>>> = IrqSafeSpinlock::new(Vec::new());
|
||||
|
||||
pci_driver! {
|
||||
matches: [class (0x01:0x06:0x01)],
|
||||
driver: {
|
||||
fn driver_name(&self) -> &str {
|
||||
"ahci"
|
||||
}
|
||||
|
||||
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
let bar5 = info.config_space.bar(5).ok_or(Error::InvalidOperation)?;
|
||||
let bar5 = bar5.as_memory().ok_or(Error::InvalidOperation)?;
|
||||
|
||||
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());
|
||||
|
||||
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
|
||||
|
||||
// // TODO support regular PCI interrupts (ACPI dependency)
|
||||
// let Some(mut msi) = info.config_space.capability::<MsiCapability>() else {
|
||||
// log::warn!("Ignoring AHCI: does not support MSI (and the OS doesn't yet support PCI IRQ)");
|
||||
// return Err(Error::InvalidOperation);
|
||||
// };
|
||||
|
||||
// Map the registers
|
||||
let regs = unsafe { DeviceMemoryIo::<Regs>::map(bar5, Default::default()) }?;
|
||||
|
||||
let version = Version::try_from(regs.VS.get())?;
|
||||
let ahci_only = regs.CAP.matches_all(CAP::SAM::SET);
|
||||
let max_port_count = regs.CAP.read(CAP::NP) as usize;
|
||||
let has_64_bit = regs.CAP.matches_all(CAP::S64A::SET);
|
||||
|
||||
// TODO extract Number of Command Slots
|
||||
|
||||
let ahci = Arc::new(AhciController {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
ports: OneTimeInit::new(),
|
||||
received_fis_buffers: OneTimeInit::new(),
|
||||
version,
|
||||
max_port_count,
|
||||
ahci_only,
|
||||
has_64_bit,
|
||||
});
|
||||
|
||||
// TODO use multiple vectors if capable
|
||||
info.map_interrupt(InterruptAffinity::Any, ahci.clone())?;
|
||||
|
||||
Ok(ahci)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ use tock_registers::{
|
||||
};
|
||||
use ygg_driver_pci::{
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
PciCommandRegister, PciConfigurationSpace,
|
||||
};
|
||||
use yggdrasil_abi::{error::Error, io::FileMode};
|
||||
@ -419,54 +420,6 @@ impl Device for NvmeController {
|
||||
// TODO
|
||||
unsafe impl Sync for NvmeController {}
|
||||
|
||||
static NVME_CONTROLLERS: IrqSafeSpinlock<Vec<Arc<NvmeController>>> =
|
||||
IrqSafeSpinlock::new(Vec::new());
|
||||
|
||||
pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
let bar0 = info
|
||||
.config_space
|
||||
.bar(0)
|
||||
.unwrap()
|
||||
.as_memory()
|
||||
.expect("Expected a memory BAR0");
|
||||
|
||||
info.init_interrupts(PreferredInterruptMode::Msi(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::<Regs>::map(bar0, Default::default()) }?;
|
||||
|
||||
// Disable the controller
|
||||
regs.CC.modify(CC::ENABLE::CLEAR);
|
||||
|
||||
let doorbell_shift = regs.CAP.read(CAP::DSTRD) as usize + 1;
|
||||
let min_page_size = 1 << (regs.CAP.read(CAP::MPSMIN) + 12);
|
||||
|
||||
if min_page_size > PAGE_SIZE {
|
||||
log::error!("Cannot support NVMe HC: min page size ({min_page_size}) > host page size ({PAGE_SIZE})");
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
|
||||
let device = NvmeController {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
admin_q: OneTimeInit::new(),
|
||||
ioqs: OneTimeInit::new(),
|
||||
drive_table: IrqSafeSpinlock::new(BTreeMap::new()),
|
||||
controller_id: OneTimeInit::new(),
|
||||
|
||||
pci: info.clone(),
|
||||
|
||||
io_queue_count: AtomicUsize::new(1),
|
||||
doorbell_shift,
|
||||
min_page_size,
|
||||
};
|
||||
|
||||
Ok(Arc::new(device))
|
||||
}
|
||||
|
||||
pub fn register_nvme_controller(controller: Arc<NvmeController>) {
|
||||
let mut list = NVME_CONTROLLERS.lock();
|
||||
let id = list.len();
|
||||
@ -498,3 +451,60 @@ pub fn register_nvme_namespace(namespace: Arc<NvmeNamespace>, probe: bool) {
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
static NVME_CONTROLLERS: IrqSafeSpinlock<Vec<Arc<NvmeController>>> =
|
||||
IrqSafeSpinlock::new(Vec::new());
|
||||
|
||||
pci_driver! {
|
||||
matches: [class (0x01:0x08:0x02)],
|
||||
driver: {
|
||||
fn driver_name(&self) -> &str {
|
||||
"nvme"
|
||||
}
|
||||
|
||||
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
let bar0 = info
|
||||
.config_space
|
||||
.bar(0)
|
||||
.unwrap()
|
||||
.as_memory()
|
||||
.expect("Expected a memory BAR0");
|
||||
|
||||
info.init_interrupts(PreferredInterruptMode::Msi(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::<Regs>::map(bar0, Default::default()) }?;
|
||||
|
||||
// Disable the controller
|
||||
regs.CC.modify(CC::ENABLE::CLEAR);
|
||||
|
||||
let doorbell_shift = regs.CAP.read(CAP::DSTRD) as usize + 1;
|
||||
let min_page_size = 1 << (regs.CAP.read(CAP::MPSMIN) + 12);
|
||||
|
||||
if min_page_size > PAGE_SIZE {
|
||||
log::error!("Cannot support NVMe HC: min page size ({min_page_size}) > host page size ({PAGE_SIZE})");
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
|
||||
let device = NvmeController {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
admin_q: OneTimeInit::new(),
|
||||
ioqs: OneTimeInit::new(),
|
||||
drive_table: IrqSafeSpinlock::new(BTreeMap::new()),
|
||||
controller_id: OneTimeInit::new(),
|
||||
|
||||
pci: info.clone(),
|
||||
|
||||
io_queue_count: AtomicUsize::new(1),
|
||||
doorbell_shift,
|
||||
min_page_size,
|
||||
};
|
||||
|
||||
Ok(Arc::new(device))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,19 +78,6 @@ pub struct PciInterruptRoute {
|
||||
pub options: IrqOptions,
|
||||
}
|
||||
|
||||
pub enum PciMatch {
|
||||
Generic(fn(&PciDeviceInfo) -> bool),
|
||||
Vendor(u16, u16),
|
||||
Class(u8, Option<u8>, Option<u8>),
|
||||
}
|
||||
|
||||
pub struct PciDriver {
|
||||
#[allow(unused)]
|
||||
pub(crate) name: &'static str,
|
||||
pub(crate) check: PciMatch,
|
||||
pub(crate) probe: fn(&PciDeviceInfo) -> Result<Arc<dyn Device>, Error>,
|
||||
}
|
||||
|
||||
/// Used to store PCI bus devices which were enumerated by the kernel
|
||||
pub struct PciBusDevice {
|
||||
pub(crate) info: PciDeviceInfo,
|
||||
|
59
kernel/driver/bus/pci/src/driver.rs
Normal file
59
kernel/driver/bus/pci/src/driver.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::device::Device;
|
||||
use libk::error::Error;
|
||||
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
|
||||
|
||||
use crate::device::PciDeviceInfo;
|
||||
|
||||
pub enum PciMatch {
|
||||
Generic(fn(&PciDeviceInfo) -> bool),
|
||||
Vendor(u16, u16),
|
||||
Class(u8, Option<u8>, Option<u8>),
|
||||
}
|
||||
|
||||
pub struct PciDriverMatch {
|
||||
pub driver: &'static dyn PciDriver,
|
||||
pub check: PciMatch,
|
||||
}
|
||||
|
||||
pub trait PciDriver: Sync {
|
||||
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error>;
|
||||
fn driver_name(&self) -> &str;
|
||||
}
|
||||
|
||||
impl PciMatch {
|
||||
pub fn check_device(&self, info: &PciDeviceInfo) -> bool {
|
||||
match self {
|
||||
Self::Generic(f) => f(info),
|
||||
&Self::Vendor(vendor_, device_) => {
|
||||
info.vendor_id == vendor_ && info.device_id == device_
|
||||
}
|
||||
&Self::Class(class_, Some(subclass_), Some(prog_if_)) => {
|
||||
class_ == info.class && subclass_ == info.subclass && prog_if_ == info.prog_if
|
||||
}
|
||||
&Self::Class(class_, Some(subclass_), _) => {
|
||||
class_ == info.class && subclass_ == info.subclass
|
||||
}
|
||||
&Self::Class(class_, _, _) => class_ == info.class,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_match(pmatch: PciMatch, driver: &'static dyn PciDriver) {
|
||||
DRIVERS.write().push(PciDriverMatch {
|
||||
check: pmatch,
|
||||
driver,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn lookup_driver(info: &PciDeviceInfo) -> Option<&'static dyn PciDriver> {
|
||||
DRIVERS.read().iter().find_map(|pmatch| {
|
||||
if pmatch.check.check_device(info) {
|
||||
Some(pmatch.driver)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
static DRIVERS: IrqSafeRwLock<Vec<PciDriverMatch>> = IrqSafeRwLock::new(Vec::new());
|
@ -1,6 +1,6 @@
|
||||
//! PCI/PCIe bus interfaces
|
||||
#![no_std]
|
||||
#![feature(let_chains)]
|
||||
#![feature(let_chains, decl_macro)]
|
||||
#![allow(clippy::missing_transmute_annotations)]
|
||||
|
||||
extern crate alloc;
|
||||
@ -12,18 +12,23 @@ use acpi::mcfg::McfgEntry;
|
||||
use alloc::{format, sync::Arc, vec::Vec};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use device::{PciBusDevice, PciDeviceInfo, PciDriver, PciMatch};
|
||||
use device::{PciBusDevice, PciDeviceInfo};
|
||||
use device_api::device::Device;
|
||||
use interrupt::PciInterruptMap;
|
||||
use libk::fs::sysfs::{self, object::KObject};
|
||||
use libk_mm::address::PhysicalAddress;
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use libk_util::{
|
||||
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
|
||||
OneTimeInit,
|
||||
};
|
||||
use space::legacy;
|
||||
use yggdrasil_abi::{error::Error, primitive_enum};
|
||||
|
||||
pub mod capability;
|
||||
pub mod device;
|
||||
pub mod driver;
|
||||
pub mod interrupt;
|
||||
pub mod macros;
|
||||
mod nodes;
|
||||
mod space;
|
||||
|
||||
@ -88,20 +93,6 @@ primitive_enum! {
|
||||
MsiX = 0x11,
|
||||
}
|
||||
}
|
||||
// /// Unique ID assigned to PCI capability structures
|
||||
// #[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
// #[non_exhaustive]
|
||||
// #[repr(u8)]
|
||||
// pub enum PciCapabilityId {
|
||||
// /// MSI (32-bit or 64-bit)
|
||||
// Msi = 0x05,
|
||||
// /// Vendor-specific capability
|
||||
// VendorSpecific = 0x09,
|
||||
// /// MSI-X
|
||||
// MsiX = 0x11,
|
||||
// /// Unknown capability missing from this list
|
||||
// Unknown,
|
||||
// }
|
||||
|
||||
/// Interface used for querying PCI capabilities
|
||||
#[allow(unused)]
|
||||
@ -609,88 +600,18 @@ fn setup_bus_device(device: &mut PciBusDevice) -> Result<(), Error> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
"{}: {:04x}:{:04x}",
|
||||
device.info.address,
|
||||
device.info.vendor_id,
|
||||
device.info.device_id
|
||||
);
|
||||
if let Some(driver) = driver::lookup_driver(&device.info) {
|
||||
log::info!("{} -> {}", device.info.address, driver.driver_name());
|
||||
let instance = driver.probe(&device.info)?;
|
||||
|
||||
let drivers = PCI_DRIVERS.lock();
|
||||
for driver in drivers.iter() {
|
||||
if driver.check.check_device(&device.info) {
|
||||
// TODO add the device to the bus
|
||||
// log::debug!(" -> {:?}", driver.name);
|
||||
let instance = (driver.probe)(&device.info)?;
|
||||
unsafe { instance.clone().init() }?;
|
||||
|
||||
unsafe { instance.clone().init() }?;
|
||||
|
||||
device.device.replace(instance);
|
||||
device.driver_name.replace(driver.name);
|
||||
break;
|
||||
}
|
||||
device.device.replace(instance);
|
||||
device.driver_name.replace(driver.driver_name());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl PciMatch {
|
||||
pub fn check_device(&self, info: &PciDeviceInfo) -> bool {
|
||||
match self {
|
||||
Self::Generic(f) => f(info),
|
||||
&Self::Vendor(vendor_, device_) => {
|
||||
info.vendor_id == vendor_ && info.device_id == device_
|
||||
}
|
||||
&Self::Class(class_, Some(subclass_), Some(prog_if_)) => {
|
||||
class_ == info.class && subclass_ == info.subclass && prog_if_ == info.prog_if
|
||||
}
|
||||
&Self::Class(class_, Some(subclass_), _) => {
|
||||
class_ == info.class && subclass_ == info.subclass
|
||||
}
|
||||
&Self::Class(class_, _, _) => class_ == info.class,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_class_driver(
|
||||
name: &'static str,
|
||||
class: u8,
|
||||
subclass: Option<u8>,
|
||||
prog_if: Option<u8>,
|
||||
probe: fn(&PciDeviceInfo) -> Result<Arc<dyn Device>, Error>,
|
||||
) {
|
||||
PCI_DRIVERS.lock().push(PciDriver {
|
||||
name,
|
||||
check: PciMatch::Class(class, subclass, prog_if),
|
||||
probe,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn register_vendor_driver(
|
||||
name: &'static str,
|
||||
vendor_id: u16,
|
||||
device_id: u16,
|
||||
probe: fn(&PciDeviceInfo) -> Result<Arc<dyn Device>, Error>,
|
||||
) {
|
||||
PCI_DRIVERS.lock().push(PciDriver {
|
||||
name,
|
||||
check: PciMatch::Vendor(vendor_id, device_id),
|
||||
probe,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn register_generic_driver(
|
||||
name: &'static str,
|
||||
check: fn(&PciDeviceInfo) -> bool,
|
||||
probe: fn(&PciDeviceInfo) -> Result<Arc<dyn Device>, Error>,
|
||||
) {
|
||||
PCI_DRIVERS.lock().push(PciDriver {
|
||||
name,
|
||||
check: PciMatch::Generic(check),
|
||||
probe,
|
||||
});
|
||||
}
|
||||
|
||||
static PCI_DRIVERS: IrqSafeSpinlock<Vec<PciDriver>> = IrqSafeSpinlock::new(Vec::new());
|
||||
static PCI_MANAGER: IrqSafeSpinlock<PciBusManager> = IrqSafeSpinlock::new(PciBusManager::new());
|
||||
static PCI_SYSFS_NODE: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
|
||||
|
@ -7,6 +7,7 @@ use rtl8139::Rtl8139;
|
||||
use rtl8168::Rtl8168;
|
||||
use ygg_driver_pci::{
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
PciBaseAddress, PciCommandRegister, PciConfigurationSpace,
|
||||
};
|
||||
|
||||
@ -15,39 +16,57 @@ extern crate alloc;
|
||||
pub mod rtl8139;
|
||||
pub mod rtl8168;
|
||||
|
||||
pub fn probe_8168(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
let base = info
|
||||
.config_space
|
||||
.bar(2)
|
||||
.and_then(PciBaseAddress::as_memory)
|
||||
.ok_or(Error::InvalidArgument)?;
|
||||
pci_driver! {
|
||||
matches: [device (0x10EC:0x8139)],
|
||||
driver: {
|
||||
fn driver_name(&self) -> &str {
|
||||
"rtl8139"
|
||||
}
|
||||
|
||||
// if let Some(power) = info.config_space.capability::<PowerManagementCapability>() {
|
||||
// power.set_device_power_state(DevicePowerState::D0);
|
||||
// }
|
||||
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
info.init_interrupts(PreferredInterruptMode::Msi(false))?;
|
||||
|
||||
// Enable MMIO + interrupts + bus mastering
|
||||
info.set_command(true, true, false, true);
|
||||
// Enable MMIO + interrupts + bus mastering
|
||||
let mut command = info.config_space.command();
|
||||
command |= (PciCommandRegister::BUS_MASTER | PciCommandRegister::ENABLE_MEMORY).bits();
|
||||
command &= !(PciCommandRegister::ENABLE_IO | PciCommandRegister::DISABLE_INTERRUPTS).bits();
|
||||
info.config_space.set_command(command);
|
||||
|
||||
let device = Rtl8168::new(base, info.clone())?;
|
||||
Ok(Arc::new(device))
|
||||
let base = info
|
||||
.config_space
|
||||
.bar(1)
|
||||
.and_then(PciBaseAddress::as_memory)
|
||||
.ok_or(Error::InvalidArgument)?;
|
||||
|
||||
let device = Rtl8139::new(base, info.clone())?;
|
||||
Ok(Arc::new(device))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn probe_8139(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
info.init_interrupts(PreferredInterruptMode::Msi(false))?;
|
||||
pci_driver! {
|
||||
matches: [device (0x10EC:0x8168)],
|
||||
driver: {
|
||||
fn driver_name(&self) -> &str {
|
||||
"rtl816x"
|
||||
}
|
||||
|
||||
// Enable MMIO + interrupts + bus mastering
|
||||
let mut command = info.config_space.command();
|
||||
command |= (PciCommandRegister::BUS_MASTER | PciCommandRegister::ENABLE_MEMORY).bits();
|
||||
command &= !(PciCommandRegister::ENABLE_IO | PciCommandRegister::DISABLE_INTERRUPTS).bits();
|
||||
info.config_space.set_command(command);
|
||||
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
let base = info
|
||||
.config_space
|
||||
.bar(2)
|
||||
.and_then(PciBaseAddress::as_memory)
|
||||
.ok_or(Error::InvalidArgument)?;
|
||||
|
||||
let base = info
|
||||
.config_space
|
||||
.bar(1)
|
||||
.and_then(PciBaseAddress::as_memory)
|
||||
.ok_or(Error::InvalidArgument)?;
|
||||
// if let Some(power) = info.config_space.capability::<PowerManagementCapability>() {
|
||||
// power.set_device_power_state(DevicePowerState::D0);
|
||||
// }
|
||||
|
||||
let device = Rtl8139::new(base, info.clone())?;
|
||||
Ok(Arc::new(device))
|
||||
// Enable MMIO + interrupts + bus mastering
|
||||
info.set_command(true, true, false, true);
|
||||
|
||||
let device = Rtl8168::new(base, info.clone())?;
|
||||
Ok(Arc::new(device))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,10 @@ use alloc::sync::Arc;
|
||||
use controller::Xhci;
|
||||
use device_api::{device::Device, interrupt::InterruptAffinity};
|
||||
use regs::Regs;
|
||||
// use regs::Mapper;
|
||||
// use xhci_lib::extended_capabilities;
|
||||
use ygg_driver_pci::{
|
||||
capability::{DevicePowerState, PowerManagementCapability},
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
PciCommandRegister, PciConfigurationSpace,
|
||||
};
|
||||
use yggdrasil_abi::error::Error;
|
||||
@ -25,37 +24,48 @@ mod regs;
|
||||
mod ring;
|
||||
mod util;
|
||||
|
||||
pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
// TODO Chip Hardware Reset
|
||||
let bar0 = info
|
||||
.config_space
|
||||
.bar(0)
|
||||
.expect("xHCI doesn't have BAR0 configured")
|
||||
.as_memory()
|
||||
.expect("xHCI's BAR0 is not memory-type");
|
||||
|
||||
if let Some(power) = info.config_space.capability::<PowerManagementCapability>() {
|
||||
log::info!("xHC has power management capability");
|
||||
let power_state = power.get_device_power_state();
|
||||
|
||||
if power_state != DevicePowerState::D0 {
|
||||
power.set_device_power_state(DevicePowerState::D0);
|
||||
// Only x86-64 supports xHCI currently, because only it has MSI-X implemented
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pci_driver! {
|
||||
matches: [class (0x0C:0x03:0x30)],
|
||||
driver: {
|
||||
fn driver_name(&self) -> &str {
|
||||
"xhci"
|
||||
}
|
||||
|
||||
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
// TODO Chip Hardware Reset
|
||||
let bar0 = info
|
||||
.config_space
|
||||
.bar(0)
|
||||
.expect("xHCI doesn't have BAR0 configured")
|
||||
.as_memory()
|
||||
.expect("xHCI's BAR0 is not memory-type");
|
||||
|
||||
if let Some(power) = info.config_space.capability::<PowerManagementCapability>() {
|
||||
log::info!("xHC has power management capability");
|
||||
let power_state = power.get_device_power_state();
|
||||
|
||||
if power_state != DevicePowerState::D0 {
|
||||
power.set_device_power_state(DevicePowerState::D0);
|
||||
}
|
||||
// Enable PME# signal generation
|
||||
power.set_pme_en(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());
|
||||
|
||||
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
|
||||
|
||||
let regs = Regs::map(bar0)?;
|
||||
let xhci = Arc::new(Xhci::new(info.clone(), regs)?);
|
||||
|
||||
info.map_interrupt(InterruptAffinity::Any, xhci.clone())?;
|
||||
|
||||
Ok(xhci)
|
||||
}
|
||||
// Enable PME# signal generation
|
||||
power.set_pme_en(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());
|
||||
|
||||
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
|
||||
|
||||
let regs = Regs::map(bar0)?;
|
||||
let xhci = Arc::new(Xhci::new(info.clone(), regs)?);
|
||||
|
||||
info.map_interrupt(InterruptAffinity::Any, xhci.clone())?;
|
||||
|
||||
Ok(xhci)
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use libk_util::{
|
||||
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
|
||||
OneTimeInit,
|
||||
};
|
||||
use ygg_driver_pci::device::PciDeviceInfo;
|
||||
use ygg_driver_pci::{device::PciDeviceInfo, macros::pci_driver};
|
||||
use ygg_driver_virtio_core::{
|
||||
queue::VirtQueue,
|
||||
transport::{pci::PciTransport, Transport},
|
||||
@ -389,17 +389,26 @@ impl<T: Transport + 'static> DisplayDevice for VirtioGpu<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
let space = &info.config_space;
|
||||
pci_driver! {
|
||||
matches: [device (0x1AF4:0x1050)],
|
||||
driver: {
|
||||
fn driver_name(&self) -> &str {
|
||||
"virtio-gpu"
|
||||
}
|
||||
|
||||
let transport = PciTransport::from_config_space(space)
|
||||
.inspect_err(|error| {
|
||||
log::error!("Couldn't set up PCI virtio transport: {error:?}");
|
||||
})
|
||||
.map_err(|_| Error::InvalidArgument)?;
|
||||
let device = VirtioGpu::new(transport, Some(info.clone()))?;
|
||||
let device = Arc::new(device);
|
||||
// let device = Box::leak(Box::new(device));
|
||||
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
let space = &info.config_space;
|
||||
|
||||
Ok(device)
|
||||
let transport = PciTransport::from_config_space(space)
|
||||
.inspect_err(|error| {
|
||||
log::error!("Couldn't set up PCI virtio transport: {error:?}");
|
||||
})
|
||||
.map_err(|_| Error::InvalidArgument)?;
|
||||
let device = VirtioGpu::new(transport, Some(info.clone()))?;
|
||||
let device = Arc::new(device);
|
||||
// let device = Box::leak(Box::new(device));
|
||||
|
||||
Ok(device)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,10 @@ use ygg_driver_net_core::{
|
||||
interface::{NetworkDevice, NetworkInterfaceType},
|
||||
Packet,
|
||||
};
|
||||
use ygg_driver_pci::device::{PciDeviceInfo, PreferredInterruptMode};
|
||||
use ygg_driver_pci::{
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
};
|
||||
use ygg_driver_virtio_core::{
|
||||
queue::VirtQueue,
|
||||
transport::{pci::PciTransport, Transport},
|
||||
@ -296,13 +299,22 @@ fn cvt_error(error: ygg_driver_virtio_core::error::Error) -> Error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
let space = &info.config_space;
|
||||
pci_driver! {
|
||||
matches: [device (0x1AF4:0x1000)],
|
||||
driver: {
|
||||
fn driver_name(&self) -> &str {
|
||||
"virtio-net"
|
||||
}
|
||||
|
||||
let transport = PciTransport::from_config_space(space).unwrap();
|
||||
let device = VirtioNet::new(transport, Some(info.clone()));
|
||||
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
let space = &info.config_space;
|
||||
|
||||
let device = Arc::new(device);
|
||||
let transport = PciTransport::from_config_space(space).unwrap();
|
||||
let device = VirtioNet::new(transport, Some(info.clone()));
|
||||
|
||||
Ok(device)
|
||||
let device = Arc::new(device);
|
||||
|
||||
Ok(device)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ use libk_mm::{
|
||||
};
|
||||
use peripherals::textfb::TextFramebuffer;
|
||||
|
||||
use crate::arch::x86;
|
||||
use crate::{arch::x86, util::call_init_array};
|
||||
|
||||
use super::Platform;
|
||||
|
||||
@ -162,8 +162,6 @@ impl I686 {
|
||||
|
||||
self.init_cpu().expect("Could not initialize CPU");
|
||||
|
||||
x86::register_pci_drivers();
|
||||
|
||||
let early = x86::init_platform_early(cmdline)?;
|
||||
|
||||
if !config::get().x86.disable_boot_fb {
|
||||
@ -173,6 +171,9 @@ impl I686 {
|
||||
}
|
||||
|
||||
x86::add_legacy_pci();
|
||||
|
||||
call_init_array();
|
||||
|
||||
x86::init_platform_devices(early);
|
||||
|
||||
Ok(())
|
||||
|
@ -50,59 +50,6 @@ pub enum SelectedClockSource {
|
||||
Fallback(Arc<I8253>),
|
||||
}
|
||||
|
||||
// TODO move this to some sort of .init_array-style implicit thing
|
||||
pub fn register_pci_drivers() {
|
||||
// XXX: Only works with MSI-X, so no i686
|
||||
// #[cfg(any(target_arch = "x86_64", rust_analyzer))]
|
||||
// ygg_driver_pci::register_class_driver(
|
||||
// "NVMe Host Controller",
|
||||
// 0x01,
|
||||
// Some(0x08),
|
||||
// Some(0x02),
|
||||
// ygg_driver_nvme::probe,
|
||||
// );
|
||||
// XXX: i686 hangs in interrupt handler
|
||||
// #[cfg(any(target_arch = "x86_64", rust_analyzer))]
|
||||
// ygg_driver_pci::register_class_driver(
|
||||
// "AHCI Controller",
|
||||
// 0x01,
|
||||
// Some(0x06),
|
||||
// Some(0x01),
|
||||
// ygg_driver_ahci::probe,
|
||||
// );
|
||||
ygg_driver_pci::register_class_driver(
|
||||
"USB xHCI",
|
||||
0x0C,
|
||||
Some(0x03),
|
||||
Some(0x30),
|
||||
ygg_driver_usb_xhci::probe,
|
||||
);
|
||||
ygg_driver_pci::register_vendor_driver(
|
||||
"Virtio PCI GPU Device",
|
||||
0x1AF4,
|
||||
0x1050,
|
||||
ygg_driver_virtio_gpu::probe,
|
||||
);
|
||||
ygg_driver_pci::register_vendor_driver(
|
||||
"Virtio PCI Network Device",
|
||||
0x1AF4,
|
||||
0x1000,
|
||||
ygg_driver_virtio_net::probe,
|
||||
);
|
||||
ygg_driver_pci::register_vendor_driver(
|
||||
"Realtek RTL8139 10/100Mbps Ethernet",
|
||||
0x10EC,
|
||||
0x8139,
|
||||
ygg_driver_net_rtl81xx::probe_8139,
|
||||
);
|
||||
ygg_driver_pci::register_vendor_driver(
|
||||
"Realtek RTL8168/8111 Gigabit Ethernet",
|
||||
0x10EC,
|
||||
0x8168,
|
||||
ygg_driver_net_rtl81xx::probe_8168,
|
||||
);
|
||||
}
|
||||
|
||||
// Initialize the bare minimum required to:
|
||||
// * Allocate/manage interrupts
|
||||
// * Print debug output
|
||||
|
@ -50,6 +50,7 @@ mod syscall;
|
||||
use crate::{
|
||||
arch::x86::{self, peripherals::hpet::Hpet},
|
||||
device::display::linear_fb::LinearFramebuffer,
|
||||
util::call_init_array,
|
||||
};
|
||||
|
||||
use self::boot::BootData;
|
||||
@ -253,8 +254,6 @@ impl X86_64 {
|
||||
self.init_local_cpu(cpu_id, available_features, enabled_features);
|
||||
|
||||
if cpu_id == 0 {
|
||||
x86::register_pci_drivers();
|
||||
|
||||
self.setup_from_boot_data()?;
|
||||
|
||||
// TODO yboot doesn't yet pass any command line options
|
||||
@ -277,6 +276,8 @@ impl X86_64 {
|
||||
log::info!("HPET disabled by config");
|
||||
}
|
||||
|
||||
call_init_array();
|
||||
|
||||
x86::init_platform_devices(early);
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
use abi::{error::Error, io::FileMode};
|
||||
use alloc::string::String;
|
||||
use arch::Platform;
|
||||
use cfg_if::cfg_if;
|
||||
use git_version::git_version;
|
||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||
use libk::{
|
||||
@ -61,6 +62,19 @@ extern crate alloc;
|
||||
#[cfg(not(rust_analyzer))]
|
||||
extern crate compiler_builtins;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_arch = "x86_64", rust_analyzer))] {
|
||||
extern crate ygg_driver_net_rtl81xx;
|
||||
extern crate ygg_driver_usb_xhci;
|
||||
extern crate ygg_driver_nvme;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern crate ygg_driver_ahci;
|
||||
extern crate ygg_driver_virtio_gpu;
|
||||
extern crate ygg_driver_virtio_net;
|
||||
|
||||
#[macro_use]
|
||||
pub mod arch;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user