|
2 | 2 |
|
3 | 3 | use alloc::collections::VecDeque;
|
4 | 4 | use alloc::vec::Vec;
|
| 5 | +#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] |
5 | 6 | use core::fmt;
|
| 7 | +#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] |
| 8 | +use core::fmt::{self, Write}; |
6 | 9 |
|
7 | 10 | use ahash::RandomState;
|
8 | 11 | use hashbrown::HashMap;
|
@@ -304,14 +307,167 @@ impl<T: ConfigRegionAccess> fmt::Display for PciDevice<T> {
|
304 | 307 | }
|
305 | 308 | }
|
306 | 309 |
|
307 |
| -pub(crate) fn print_information() { |
| 310 | +// Currently, this function is only implemented for x86_64 |
| 311 | +// TODO: Implement reading PCI information from devicetree on aarch64 |
| 312 | +#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] |
| 313 | +fn print_from_fdt() -> Result<(), ()> { |
| 314 | + let mut f = alloc::string::String::new(); |
| 315 | + |
| 316 | + let fdt = env::fdt().ok_or(())?; |
| 317 | + |
| 318 | + infoheader!(" PCI BUS INFORMATION "); |
| 319 | + |
| 320 | + if let Some(pci) = fdt.find_node("/pci") { |
| 321 | + for node in pci.children() { |
| 322 | + let reg = node.property("reg").unwrap().value; |
| 323 | + let addr = u32::from_be_bytes(reg[0..4].try_into().unwrap()); |
| 324 | + |
| 325 | + let pci_config = PciConfigRegion::new(); |
| 326 | + |
| 327 | + let pci_address = PciAddress::new( |
| 328 | + 0, |
| 329 | + ((addr >> 16) & 0xff) as u8, |
| 330 | + ((addr >> 11) & 0x1f) as u8, |
| 331 | + 0, |
| 332 | + ); |
| 333 | + |
| 334 | + let vendor_id = u32::from_be_bytes( |
| 335 | + node.property("vendor-id").unwrap().value[..] |
| 336 | + .try_into() |
| 337 | + .unwrap(), |
| 338 | + ) as u16; |
| 339 | + let device_id = u32::from_be_bytes( |
| 340 | + node.property("device-id").unwrap().value[..] |
| 341 | + .try_into() |
| 342 | + .unwrap(), |
| 343 | + ) as u16; |
| 344 | + |
| 345 | + let header = PciHeader::new(pci_address); |
| 346 | + let (_dev_rev, class_id, subclass_id, _interface) = |
| 347 | + header.revision_and_class(pci_config); |
| 348 | + |
| 349 | + #[cfg(feature = "pci-ids")] |
| 350 | + let (class_name, vendor_name, device_name) = { |
| 351 | + use pci_ids::{Class, Device, FromId, Subclass}; |
| 352 | + |
| 353 | + let class_name = Class::from_id(class_id).map_or("Unknown Class", |class| { |
| 354 | + class |
| 355 | + .subclasses() |
| 356 | + .find(|s| s.id() == subclass_id) |
| 357 | + .map(Subclass::name) |
| 358 | + .unwrap_or_else(|| class.name()) |
| 359 | + }); |
| 360 | + |
| 361 | + let (vendor_name, device_name) = Device::from_vid_pid(vendor_id, device_id) |
| 362 | + .map(|device| (device.vendor().name(), device.name())) |
| 363 | + .unwrap_or(("Unknown Vendor", "Unknown Device")); |
| 364 | + |
| 365 | + (class_name, vendor_name, device_name) |
| 366 | + }; |
| 367 | + |
| 368 | + #[cfg(not(feature = "pci-ids"))] |
| 369 | + let (class_name, vendor_name, device_name) = |
| 370 | + ("Unknown Class", "Unknown Vendor", "Unknown Device"); |
| 371 | + |
| 372 | + // Output detailed readable information about this device. |
| 373 | + write!( |
| 374 | + &mut f, |
| 375 | + "{:02X}:{:02X} {} [{:02X}{:02X}]: {} {} [{:04X}:{:04X}]", |
| 376 | + pci_address.bus(), |
| 377 | + pci_address.device(), |
| 378 | + class_name, |
| 379 | + class_id, |
| 380 | + subclass_id, |
| 381 | + vendor_name, |
| 382 | + device_name, |
| 383 | + vendor_id, |
| 384 | + device_id |
| 385 | + ) |
| 386 | + .unwrap(); |
| 387 | + |
| 388 | + // If the devices uses an IRQ, output this one as well. |
| 389 | + if let Some(irq_prop) = node.property("interrupts") { |
| 390 | + let irq = u32::from_be_bytes(irq_prop.value[..].try_into().unwrap()) as u8; |
| 391 | + |
| 392 | + if irq != 0 && irq != u8::MAX { |
| 393 | + write!(&mut f, ", IRQ {irq}").unwrap(); |
| 394 | + } |
| 395 | + } |
| 396 | + |
| 397 | + let mut assigned_addresses = node.property("assigned-addresses").unwrap().value; |
| 398 | + let mut value_slice; |
| 399 | + |
| 400 | + let mut slot: u8 = 0; |
| 401 | + while !assigned_addresses.is_empty() { |
| 402 | + (value_slice, assigned_addresses) = |
| 403 | + assigned_addresses.split_at(core::mem::size_of::<u32>()); |
| 404 | + let bar = u32::from_be_bytes(value_slice.try_into().unwrap()); |
| 405 | + |
| 406 | + match bar ^ addr { |
| 407 | + 0x8100_0014 => { |
| 408 | + (value_slice, assigned_addresses) = |
| 409 | + assigned_addresses.split_at(core::mem::size_of::<u64>()); |
| 410 | + let port = u64::from_be_bytes(value_slice.try_into().unwrap()); |
| 411 | + (value_slice, assigned_addresses) = |
| 412 | + assigned_addresses.split_at(core::mem::size_of::<u64>()); |
| 413 | + let _size = u64::from_be_bytes(value_slice.try_into().unwrap()); |
| 414 | + write!(&mut f, ", BAR{slot} IO {{ port: {port:#X} }}").unwrap(); |
| 415 | + } |
| 416 | + 0x8200_0010 => { |
| 417 | + (value_slice, assigned_addresses) = |
| 418 | + assigned_addresses.split_at(core::mem::size_of::<u64>()); |
| 419 | + let address = u64::from_be_bytes(value_slice.try_into().unwrap()); |
| 420 | + (value_slice, assigned_addresses) = |
| 421 | + assigned_addresses.split_at(core::mem::size_of::<u64>()); |
| 422 | + let size = u64::from_be_bytes(value_slice.try_into().unwrap()); |
| 423 | + |
| 424 | + if address.leading_zeros() >= 32 && size.leading_zeros() >= 32 { |
| 425 | + write!( |
| 426 | + &mut f, |
| 427 | + ", BAR{slot} Memory32 {{ address: {address:#X}, size: {size:#X} }}" |
| 428 | + ) |
| 429 | + .unwrap(); |
| 430 | + } else { |
| 431 | + write!( |
| 432 | + &mut f, |
| 433 | + ", BAR{slot} Memory64 {{ address: {address:#X}, size: {size:#X} }}" |
| 434 | + ) |
| 435 | + .unwrap(); |
| 436 | + slot += 1; |
| 437 | + } |
| 438 | + } |
| 439 | + _ => {} |
| 440 | + } |
| 441 | + slot += 1; |
| 442 | + } |
| 443 | + } |
| 444 | + } |
| 445 | + |
| 446 | + info!("{}", f); |
| 447 | + |
| 448 | + infofooter!(); |
| 449 | + |
| 450 | + Ok(()) |
| 451 | +} |
| 452 | + |
| 453 | +fn print_from_pci() -> Result<(), ()> { |
308 | 454 | infoheader!(" PCI BUS INFORMATION ");
|
309 | 455 |
|
310 | 456 | for adapter in PCI_DEVICES.finalize().iter() {
|
311 | 457 | info!("{}", adapter);
|
312 | 458 | }
|
313 | 459 |
|
314 | 460 | infofooter!();
|
| 461 | + |
| 462 | + Ok(()) |
| 463 | +} |
| 464 | + |
| 465 | +pub(crate) fn print_information() { |
| 466 | + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] |
| 467 | + print_from_fdt().or_else(|_e| print_from_pci()).unwrap(); |
| 468 | + |
| 469 | + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] |
| 470 | + print_from_pci().unwrap(); |
315 | 471 | }
|
316 | 472 |
|
317 | 473 | #[allow(clippy::large_enum_variant)]
|
@@ -472,7 +628,44 @@ pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptTicketMutex<Vi
|
472 | 628 | .find_map(|drv| drv.get_filesystem_driver())
|
473 | 629 | }
|
474 | 630 |
|
475 |
| -pub(crate) fn init() { |
| 631 | +fn init_from_fdt() -> Result<(), ()> { |
| 632 | + let fdt = env::fdt().ok_or(())?; |
| 633 | + |
| 634 | + info!( |
| 635 | + "Initializing PCI devices from FDT at {:#x}", |
| 636 | + core::ptr::from_ref::<fdt::Fdt<'_>>(&fdt) as usize |
| 637 | + ); |
| 638 | + |
| 639 | + #[cfg(feature = "rtl8139")] |
| 640 | + if let Some(node) = fdt.find_compatible(&["realtek,rtl8139"]) { |
| 641 | + info!( |
| 642 | + "Found Realtek network device with device id {:#x}", |
| 643 | + node.property("device-id").unwrap().as_usize().unwrap() |
| 644 | + ); |
| 645 | + |
| 646 | + let reg = node.property("reg").unwrap().value; |
| 647 | + let addr = u32::from_be_bytes(reg[0..4].try_into().unwrap()); |
| 648 | + |
| 649 | + let pci_config = PciConfigRegion::new(); |
| 650 | + |
| 651 | + let pci_address = PciAddress::new( |
| 652 | + 0, |
| 653 | + ((addr >> 16) & 0xff) as u8, |
| 654 | + ((addr >> 11) & 0x1f) as u8, |
| 655 | + 0, |
| 656 | + ); |
| 657 | + |
| 658 | + let adapter = PciDevice::new(pci_address, pci_config); |
| 659 | + |
| 660 | + if let Ok(drv) = rtl8139::init_device(&adapter) { |
| 661 | + register_driver(PciDriver::RTL8139Net(InterruptTicketMutex::new(drv))) |
| 662 | + } |
| 663 | + } |
| 664 | + |
| 665 | + Ok(()) |
| 666 | +} |
| 667 | + |
| 668 | +fn init_from_pci() -> Result<(), ()> { |
476 | 669 | // virtio: 4.1.2 PCI Device Discovery
|
477 | 670 | without_interrupts(|| {
|
478 | 671 | for adapter in PCI_DEVICES.finalize().iter().filter(|x| {
|
@@ -522,6 +715,12 @@ pub(crate) fn init() {
|
522 | 715 | }
|
523 | 716 | }
|
524 | 717 | });
|
| 718 | + |
| 719 | + Ok(()) |
| 720 | +} |
| 721 | + |
| 722 | +pub(crate) fn init() { |
| 723 | + init_from_fdt().or_else(|_e| init_from_pci()).unwrap(); |
525 | 724 | }
|
526 | 725 |
|
527 | 726 | /// A module containing PCI specific errors
|
|
0 commit comments