Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read PCI devices through devicetree instead of scanning PCI bus in kernel #1476

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,16 @@ harness = false
default = ["pci", "pci-ids", "acpi", "fsgsbase", "smp", "tcp", "dhcpv4", "fuse", "vsock"]
acpi = []
common-os = []
dhcpv4 = ["smoltcp", "smoltcp/proto-dhcpv4", "smoltcp/socket-dhcpv4"]
dhcpv4 = [
"smoltcp",
"smoltcp/proto-dhcpv4",
"smoltcp/socket-dhcpv4",
]
dns = ["smoltcp", "smoltcp/socket-dns"]
fdt = []
fs = ["fuse"]
fsgsbase = []
fuse = ["pci", "dep:fuse-abi", "fuse-abi/num_enum"]
fsgsbase = []
gem-net = ["tcp", "dep:tock-registers"]
idle-poll = []
mmap = []
Expand Down
6 changes: 6 additions & 0 deletions src/arch/x86_64/kernel/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ impl ConfigRegionAccess for PciConfigRegion {
}
}

#[cfg(not(feature = "fdt"))]
pub(crate) fn init() {
debug!("Scanning PCI Busses 0 to {}", PCI_MAX_BUS_NUMBER - 1);

Expand All @@ -68,3 +69,8 @@ pub(crate) fn init() {
}
}
}

#[cfg(feature = "fdt")]
pub(crate) fn init() {
// Do nothing here, as the PCI devices are scanned in the device tree.
}
155 changes: 154 additions & 1 deletion src/drivers/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use alloc::collections::VecDeque;
use alloc::vec::Vec;
use core::fmt;
use core::fmt::{self, Write};

use ahash::RandomState;
use hashbrown::HashMap;
Expand Down Expand Up @@ -304,6 +304,7 @@ impl<T: ConfigRegionAccess> fmt::Display for PciDevice<T> {
}
}

#[cfg(not(feature = "fdt"))]
pub(crate) fn print_information() {
infoheader!(" PCI BUS INFORMATION ");

Expand All @@ -314,6 +315,124 @@ pub(crate) fn print_information() {
infofooter!();
}

#[cfg(feature = "fdt")]
pub(crate) fn print_information() {
let mut f = alloc::string::String::new();

let fdt = env::fdt().expect("Failed to get FDT");

infoheader!(" PCI BUS INFORMATION ");

if let Some(pci) = fdt.find_node("/pci") {
for node in pci.children() {
let reg = node.property("reg").unwrap().value;
let addr = u32::from_be_bytes(reg[0..4].try_into().unwrap());

let pci_config = PciConfigRegion::new();

let pci_address = PciAddress::new(
0,
((addr >> 16) & 0xFF) as u8,
((addr >> 11) & 0x1F) as u8,
0,
);

let vendor_id = u32::from_be_bytes(node.property("vendor-id").unwrap().value[..].try_into().unwrap()) as u16;
let device_id = u32::from_be_bytes(node.property("device-id").unwrap().value[..].try_into().unwrap()) as u16;

let header = PciHeader::new(pci_address);
let (_dev_rev, class_id, subclass_id, _interface) = header.revision_and_class(pci_config);

#[cfg(feature = "pci-ids")]
let (class_name, vendor_name, device_name) = {
use pci_ids::{Class, Device, FromId, Subclass};

let class_name = Class::from_id(class_id).map_or("Unknown Class", |class| {
class
.subclasses()
.find(|s| s.id() == subclass_id)
.map(Subclass::name)
.unwrap_or_else(|| class.name())
});

let (vendor_name, device_name) = Device::from_vid_pid(vendor_id, device_id)
.map(|device| (device.vendor().name(), device.name()))
.unwrap_or(("Unknown Vendor", "Unknown Device"));

(class_name, vendor_name, device_name)
};

#[cfg(not(feature = "pci-ids"))]
let (class_name, vendor_name, device_name) =
("Unknown Class", "Unknown Vendor", "Unknown Device");

// Output detailed readable information about this device.
write!(
&mut f,
"{:02X}:{:02X} {} [{:02X}{:02X}]: {} {} [{:04X}:{:04X}]",
pci_address.bus(),
pci_address.device(),
class_name,
class_id,
subclass_id,
vendor_name,
device_name,
vendor_id,
device_id
);

// If the devices uses an IRQ, output this one as well.
if let Some(irq_prop) = node.property("interrupts") {
let irq = u32::from_be_bytes(irq_prop.value[..].try_into().unwrap()) as u8;

if irq != 0 && irq != u8::MAX {
write!(&mut f, ", IRQ {irq}");
}
}

let mut assigned_addresses = node.property("assigned-addresses").unwrap().value;
let mut value_slice;

let mut slot: u8 = 0;
while !assigned_addresses.is_empty() {
(value_slice, assigned_addresses) = assigned_addresses.split_at(core::mem::size_of::<u32>());
let bar = u32::from_be_bytes(value_slice.try_into().unwrap());

match bar ^ addr {
0x81000014 => {
(value_slice, assigned_addresses) = assigned_addresses.split_at(core::mem::size_of::<u64>());
let port = u64::from_be_bytes(value_slice.try_into().unwrap());
(value_slice, assigned_addresses) = assigned_addresses.split_at(core::mem::size_of::<u64>());
let _size = u64::from_be_bytes(value_slice.try_into().unwrap());
write!(&mut f, ", BAR{slot} IO {{ port: {port:#X} }}");
}
0x82000010 => {
(value_slice, assigned_addresses) = assigned_addresses.split_at(core::mem::size_of::<u64>());
let address = u64::from_be_bytes(value_slice.try_into().unwrap());
(value_slice, assigned_addresses) = assigned_addresses.split_at(core::mem::size_of::<u64>());
let size = u64::from_be_bytes(value_slice.try_into().unwrap());

if address.leading_zeros() >= 32 && size.leading_zeros() >= 32 {
write!(&mut f, ", BAR{slot} Memory32 {{ address: {address:#X}, size: {size:#X} }}");
} else {
write!(&mut f, ", BAR{slot} Memory64 {{ address: {address:#X}, size: {size:#X} }}");
slot += 1;
}
}
_ => {}
}
slot += 1;
}


}
}

info!("{}", f);

infofooter!();
}

#[allow(clippy::large_enum_variant)]
#[allow(clippy::enum_variant_names)]
pub(crate) enum PciDriver {
Expand Down Expand Up @@ -472,6 +591,7 @@ pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptTicketMutex<Vi
.find_map(|drv| drv.get_filesystem_driver())
}

#[cfg(not(feature = "fdt"))]
pub(crate) fn init() {
// virtio: 4.1.2 PCI Device Discovery
without_interrupts(|| {
Expand Down Expand Up @@ -524,6 +644,39 @@ pub(crate) fn init() {
});
}

#[cfg(feature = "fdt")]
pub(crate) fn init() {
without_interrupts(|| {
let fdt = env::fdt().expect("Failed to get FDT");

#[cfg(feature = "rtl8139")]
if let Some(node) = fdt.find_compatible(&["realtek,rtl8139"]) {
info!(
"Found Realtek network device with device id {:#x}",
node.property("device-id").unwrap().as_usize().unwrap()
);

let reg = node.property("reg").unwrap().value;
let addr = u32::from_be_bytes(reg[0..4].try_into().unwrap());

let pci_config = PciConfigRegion::new();

let pci_address = PciAddress::new(
0,
((addr >> 16) & 0xFF) as u8,
((addr >> 11) & 0x1F) as u8,
0,
);

let adapter = PciDevice::new(pci_address, pci_config);

if let Ok(drv) = rtl8139::init_device(&adapter) {
register_driver(PciDriver::RTL8139Net(InterruptTicketMutex::new(drv)))
}
}
});
}

/// A module containing PCI specific errors
///
/// Errors include...
Expand Down
Loading