diff --git a/Cargo.lock b/Cargo.lock index 29db9ad7..b47b6483 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,7 +57,7 @@ dependencies = [ [[package]] name = "acpi-system" version = "0.1.0" -source = "git+https://github.com/alnyan/acpi-system.git#2e57911ab3df43dac7227a3fa458eac6981bbbf9" +source = "git+https://github.com/alnyan/acpi-system.git#1dfbf5d22d9227ccdd02e670d1adebca64173040" dependencies = [ "acpi", "aml", @@ -1838,9 +1838,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "same-file" @@ -2229,9 +2229,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "unicode-width" @@ -2531,9 +2531,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.24" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310" dependencies = [ "memchr", ] @@ -2734,6 +2734,7 @@ dependencies = [ "acpi", "bitflags 2.8.0", "device-api", + "kernel-arch-x86", "libk", "libk-mm", "libk-util", diff --git a/kernel/driver/block/ahci/src/lib.rs b/kernel/driver/block/ahci/src/lib.rs index c4414e5f..be42d0bd 100644 --- a/kernel/driver/block/ahci/src/lib.rs +++ b/kernel/driver/block/ahci/src/lib.rs @@ -202,7 +202,7 @@ pub fn probe(info: &PciDeviceInfo) -> Result, Error> { cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER; info.config_space.set_command(cmd.bits()); - info.init_interrupts(PreferredInterruptMode::Msi)?; + info.init_interrupts(PreferredInterruptMode::Msi(true))?; // // TODO support regular PCI interrupts (ACPI dependency) // let Some(mut msi) = info.config_space.capability::() else { diff --git a/kernel/driver/block/nvme/src/lib.rs b/kernel/driver/block/nvme/src/lib.rs index 22d3cbc0..b7f9e141 100644 --- a/kernel/driver/block/nvme/src/lib.rs +++ b/kernel/driver/block/nvme/src/lib.rs @@ -428,7 +428,7 @@ pub fn probe(info: &PciDeviceInfo) -> Result, Error> { .as_memory() .expect("Expected a memory BAR0"); - info.init_interrupts(PreferredInterruptMode::Msi)?; + info.init_interrupts(PreferredInterruptMode::Msi(true))?; let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command()); cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO); diff --git a/kernel/driver/bus/pci/Cargo.toml b/kernel/driver/bus/pci/Cargo.toml index 7f43f5e6..c06f5ee3 100644 --- a/kernel/driver/bus/pci/Cargo.toml +++ b/kernel/driver/bus/pci/Cargo.toml @@ -18,6 +18,7 @@ tock-registers.workspace = true [target.'cfg(target_arch = "x86_64")'.dependencies] ygg_driver_acpi.path = "../../acpi" acpi.workspace = true +kernel-arch-x86.workspace = true [lints] workspace = true diff --git a/kernel/driver/bus/pci/src/capability.rs b/kernel/driver/bus/pci/src/capability.rs index 501d0474..4f7f4e44 100644 --- a/kernel/driver/bus/pci/src/capability.rs +++ b/kernel/driver/bus/pci/src/capability.rs @@ -1,9 +1,12 @@ //! PCI capability structures and queries +use core::mem::offset_of; + use alloc::{sync::Arc, vec, vec::Vec}; use device_api::interrupt::{ InterruptAffinity, InterruptHandler, MessageInterruptController, MsiInfo, }; +use kernel_arch_x86::intrinsics; use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut}; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -11,6 +14,8 @@ use tock_registers::{ }; use yggdrasil_abi::error::Error; +use crate::PciBaseAddress; + use super::{PciCapability, PciCapabilityId, PciConfigurationSpace}; pub trait VirtioCapabilityData<'s, S: PciConfigurationSpace + ?Sized + 's>: Sized { @@ -41,6 +46,9 @@ pub trait VirtioCapability { type Output<'a, S: PciConfigurationSpace + ?Sized + 'a>: VirtioCapabilityData<'a, S>; } +/// Power management capability entry +pub struct PowerManagementCapability; + /// MSI-X capability query pub struct MsiXCapability; @@ -57,6 +65,15 @@ pub struct VirtioNotifyConfigCapability; /// VirtIO interrupt status pub struct VirtioInterruptStatusCapability; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DevicePowerState { + D0, + D1, + D2, + D3Cold, + D3Hot, +} + /// Represents an entry in MSI-X vector table #[repr(C)] pub struct MsiXEntry { @@ -68,8 +85,20 @@ pub struct MsiXEntry { pub control: ReadWrite, } +enum MsiXVectorTableAccess<'a> { + Memory(DeviceMemoryIoMut<'a, [MsiXEntry]>), + Io(u16), +} + pub struct MsiXVectorTable<'a> { - vectors: DeviceMemoryIoMut<'a, [MsiXEntry]>, + access: MsiXVectorTableAccess<'a>, + len: usize, +} + +/// PCI Power Management capability data structure +pub struct PowerManagementData<'s, S: PciConfigurationSpace + ?Sized + 's> { + space: &'s S, + offset: usize, } /// MSI-X capability data structure @@ -122,6 +151,19 @@ impl PciCapability for T { } } +impl PciCapability for PowerManagementCapability { + const ID: PciCapabilityId = PciCapabilityId::PowerManagement; + type CapabilityData<'a, S: PciConfigurationSpace + ?Sized + 'a> = PowerManagementData<'a, S>; + + fn data<'s, S: PciConfigurationSpace + ?Sized + 's>( + space: &'s S, + offset: usize, + _len: usize, + ) -> Self::CapabilityData<'s, S> { + PowerManagementData { space, offset } + } +} + impl PciCapability for MsiXCapability { const ID: PciCapabilityId = PciCapabilityId::MsiX; type CapabilityData<'a, S: PciConfigurationSpace + ?Sized + 'a> = MsiXData<'a, S>; @@ -246,6 +288,40 @@ impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioCapabilityData<'s, S> } } +impl<'s, S: PciConfigurationSpace + ?Sized + 's> PowerManagementData<'s, S> { + pub fn set_device_power_state(&self, state: DevicePowerState) { + let pmcsr = self.space.read_u16(self.offset + 4) & !0x3; + let current = self.get_device_power_state(); + + if state == current { + return; + } + + log::info!("Set device power state: {state:?}"); + + match state { + DevicePowerState::D0 => { + // power = 0b00 | PME_EN + self.space.write_u16(self.offset + 4, pmcsr); + } + _ => { + log::warn!("TODO: {state:?} power state"); + } + } + } + + pub fn get_device_power_state(&self) -> DevicePowerState { + let pmcsr = self.space.read_u16(self.offset + 4); + match pmcsr & 0x3 { + 0b00 => DevicePowerState::D0, + 0b01 => DevicePowerState::D1, + 0b10 => DevicePowerState::D2, + 0b11 => DevicePowerState::D3Hot, + _ => unreachable!(), + } + } +} + impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiXData<'s, S> { // TODO use pending bits as well /// Maps and returns the vector table associated with the device's MSI-X capability @@ -260,13 +336,27 @@ impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiXData<'s, S> { let Some(base) = self.space.bar(bir) else { return Err(Error::DoesNotExist); }; - let Some(base) = base.as_memory() else { - return Err(Error::InvalidOperation); - }; - log::debug!("MSI-X table address: {:#x}", base.add(table_offset)); - - unsafe { MsiXVectorTable::from_raw_parts(base.add(table_offset), table_size) } + match base { + PciBaseAddress::Memory32(mem32) => unsafe { + log::info!("MSI-X table address: {:#x}", mem32 + table_offset as u32); + MsiXVectorTable::memory_from_raw_parts( + PhysicalAddress::from_u32(mem32).add(table_offset), + table_size, + ) + }, + PciBaseAddress::Memory64(mem64) => unsafe { + log::info!("MSI-X table address: {:#x}", mem64 + table_offset as u64); + MsiXVectorTable::memory_from_raw_parts( + PhysicalAddress::from_u64(mem64).add(table_offset), + table_size, + ) + }, + PciBaseAddress::Io(io) => unsafe { + log::info!("MSI-X table I/O: {:#x}", io + table_offset as u16); + MsiXVectorTable::io_from_raw_parts(io + table_offset as u16, table_size) + }, + } } /// Changes the global enable status for the device's MSI-X capability. If set, regular IRQs @@ -292,15 +382,79 @@ impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiXData<'s, S> { } } +impl MsiXVectorTableAccess<'_> { + fn set_vector_masked(&mut self, vector: usize, masked: bool) { + let old = self.read_control(vector); + let new = if masked { old | 1 } else { old & !1 }; + if old != new { + self.write_control(vector, new); + } + } + + fn read_control(&mut self, vector: usize) -> u32 { + match self { + &mut Self::Io(base) => unsafe { + let a = base + + (vector * size_of::() + offset_of!(MsiXEntry, control)) as u16; + intrinsics::inl(a) + }, + Self::Memory(vectors) => vectors[vector].control.get(), + } + } + + fn write_address(&mut self, vector: usize, value: u64) { + match self { + &mut Self::Io(base) => unsafe { + let a = base + (vector * size_of::()) as u16; + intrinsics::outl(a, value as u32); + intrinsics::outl(a + 4, (value >> 32) as u32); + }, + Self::Memory(vectors) => vectors[vector].address.set(value), + } + } + + fn write_data(&mut self, vector: usize, value: u32) { + match self { + &mut Self::Io(base) => unsafe { + let a = + base + (vector * size_of::() + offset_of!(MsiXEntry, data)) as u16; + intrinsics::outl(a, value) + }, + Self::Memory(vectors) => vectors[vector].data.set(value), + } + } + + fn write_control(&mut self, vector: usize, value: u32) { + match self { + &mut Self::Io(base) => unsafe { + let a = base + + (vector * size_of::() + offset_of!(MsiXEntry, control)) as u16; + intrinsics::outl(a, value) + }, + Self::Memory(vectors) => vectors[vector].control.set(value), + } + } +} + impl MsiXVectorTable<'_> { - unsafe fn from_raw_parts(base: PhysicalAddress, len: usize) -> Result { + unsafe fn memory_from_raw_parts(base: PhysicalAddress, len: usize) -> Result { let vectors = DeviceMemoryIoMut::map_slice(base, len, Default::default())?; - Ok(Self { vectors }) + Ok(Self { + access: MsiXVectorTableAccess::Memory(vectors), + len, + }) + } + + unsafe fn io_from_raw_parts(base: u16, len: usize) -> Result { + Ok(Self { + access: MsiXVectorTableAccess::Io(base), + len, + }) } pub fn mask_all(&mut self) { - for vector in self.vectors.iter_mut() { - vector.set_masked(true); + for i in 0..self.len { + self.access.set_vector_masked(i, true); } } @@ -324,26 +478,15 @@ impl MsiXVectorTable<'_> { for (i, info) in range.iter().enumerate() { let index = i + start; - self.vectors[index].address.set(info.address as _); - self.vectors[index].data.set(info.value); - self.vectors[index].set_masked(false); + self.access.write_address(index, info.address as _); + self.access.write_data(index, info.value); + self.access.set_vector_masked(index, false); } Ok(range) } } -impl MsiXEntry { - /// If set, prevents the MSI-X interrupt from being delivered - fn set_masked(&mut self, masked: bool) { - if masked { - self.control.set(self.control.get() | 1); - } else { - self.control.set(self.control.get() & !1); - } - } -} - impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiData<'s, S> { pub fn register( &mut self, diff --git a/kernel/driver/bus/pci/src/device.rs b/kernel/driver/bus/pci/src/device.rs index 81f19a79..f13e6fbe 100644 --- a/kernel/driver/bus/pci/src/device.rs +++ b/kernel/driver/bus/pci/src/device.rs @@ -11,7 +11,7 @@ use yggdrasil_abi::error::Error; use crate::{ capability::{MsiCapability, MsiXCapability, MsiXVectorTable}, - PciAddress, PciConfigSpace, PciConfigurationSpace, PciSegmentInfo, + PciAddress, PciCommandRegister, PciConfigSpace, PciConfigurationSpace, PciSegmentInfo, }; /// Describes a PCI device @@ -53,7 +53,7 @@ pub enum PciInterruptPin { #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum PreferredInterruptMode { - Msi, + Msi(bool), Legacy, } @@ -85,6 +85,7 @@ pub enum PciMatch { } pub struct PciDriver { + #[allow(unused)] pub(crate) name: &'static str, pub(crate) check: PciMatch, pub(crate) probe: fn(&PciDeviceInfo) -> Result, Error>, @@ -98,29 +99,77 @@ pub struct PciBusDevice { } impl PciDeviceInfo { + pub fn set_command( + &self, + enable_irq: bool, + enable_mem: bool, + enable_io: bool, + enable_bus_master: bool, + ) { + let command = PciCommandRegister::from_bits_retain(self.config_space.command()); + let mut new = command; + if enable_irq { + new &= !PciCommandRegister::DISABLE_INTERRUPTS; + } else { + new |= PciCommandRegister::DISABLE_INTERRUPTS; + } + if enable_mem { + new |= PciCommandRegister::ENABLE_MEMORY; + } else { + new &= !PciCommandRegister::ENABLE_MEMORY; + } + if enable_io { + new |= PciCommandRegister::ENABLE_IO; + } else { + new &= !PciCommandRegister::ENABLE_IO; + } + if enable_bus_master { + new |= PciCommandRegister::BUS_MASTER; + } else { + new &= !PciCommandRegister::BUS_MASTER; + } + if new != command { + self.config_space.set_command(new.bits()); + } + } + pub fn init_interrupts(&self, preferred_mode: PreferredInterruptMode) -> Result<(), Error> { self.interrupt_config .try_init_with(|| { - let configured_mode = - if self.segment.has_msi && preferred_mode == PreferredInterruptMode::Msi { - if let Some(mut msix) = self.config_space.capability::() { - let mut vt = msix.vector_table().unwrap(); - + let configured_mode = if self.segment.has_msi + && let PreferredInterruptMode::Msi(want_msix) = preferred_mode + { + // Try MSI-X first + let mut result = None; + if want_msix + && let Some(mut msix) = self.config_space.capability::() + { + if let Ok(mut vt) = msix.vector_table() { vt.mask_all(); msix.set_function_mask(false); msix.set_enabled(true); - ConfiguredInterruptMode::MsiX(vt) - } else if self.config_space.capability::().is_some() { - ConfiguredInterruptMode::Msi - } else { - self.legacy_interrupt_mode() + result = Some(ConfiguredInterruptMode::MsiX(vt)); } + } + + // Then try MSI + if result.is_none() && self.config_space.capability::().is_some() + { + result = Some(ConfiguredInterruptMode::Msi) + } + + // And then fall back to legacy + if let Some(result) = result { + result } else { - // Ignore preferred_mode, the only supported is Legacy self.legacy_interrupt_mode() - }; + } + } else { + // Ignore preferred_mode, the only supported is Legacy + self.legacy_interrupt_mode() + }; IrqSafeRwLock::new(InterruptConfig { preferred_mode, configured_mode, diff --git a/kernel/driver/bus/pci/src/interrupt.rs b/kernel/driver/bus/pci/src/interrupt.rs index 578394d9..a2b06155 100644 --- a/kernel/driver/bus/pci/src/interrupt.rs +++ b/kernel/driver/bus/pci/src/interrupt.rs @@ -33,6 +33,14 @@ impl PciInterruptMap { interrupt.address.function as u16, aml_pin, ) + .or_else(|| { + ygg_driver_acpi::get_pci_route( + aml_object_name.as_str(), + interrupt.address.device as u16, + 0xFFFF, + aml_pin, + ) + }) .ok_or(Error::DoesNotExist)?; let trigger = match aml_route.trigger { diff --git a/kernel/driver/bus/pci/src/lib.rs b/kernel/driver/bus/pci/src/lib.rs index 91c576a2..f02a5481 100644 --- a/kernel/driver/bus/pci/src/lib.rs +++ b/kernel/driver/bus/pci/src/lib.rs @@ -1,5 +1,6 @@ //! PCI/PCIe bus interfaces #![no_std] +#![feature(let_chains)] #![allow(clippy::missing_transmute_annotations)] extern crate alloc; @@ -18,7 +19,7 @@ use libk::fs::sysfs::{self, object::KObject}; use libk_mm::address::PhysicalAddress; use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; use space::legacy; -use yggdrasil_abi::error::Error; +use yggdrasil_abi::{error::Error, primitive_enum}; pub mod capability; pub mod device; @@ -34,6 +35,7 @@ pub use space::{ bitflags! { /// Command register of the PCI configuration space + #[derive(PartialEq, Clone, Copy)] pub struct PciCommandRegister: u16 { /// If set, I/O access to the device is enabled const ENABLE_IO = 1 << 0; @@ -78,20 +80,28 @@ pub enum PciBaseAddress { Io(u16), } -/// 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, +primitive_enum! { + pub enum PciCapabilityId: u8 { + PowerManagement = 0x01, + Msi = 0x05, + VendorSpecific = 0x09, + 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)] @@ -429,9 +439,9 @@ impl PciBusManager { /// Walks the bus device list and calls init/init_irq functions on any devices with associated /// drivers pub fn setup_bus_devices() -> Result<(), Error> { - log::info!("Setting up bus devices"); + // log::info!("Setting up bus devices"); Self::walk_bus_devices(|device| { - log::info!("Set up {}", device.info.address); + // log::info!("Set up {}", device.info.address); setup_bus_device(device)?; Ok(true) }) @@ -610,7 +620,7 @@ fn setup_bus_device(device: &mut PciBusDevice) -> Result<(), Error> { for driver in drivers.iter() { if driver.check.check_device(&device.info) { // TODO add the device to the bus - log::debug!(" -> {:?}", driver.name); + // log::debug!(" -> {:?}", driver.name); let instance = (driver.probe)(&device.info)?; unsafe { instance.clone().init() }?; diff --git a/kernel/driver/bus/pci/src/nodes.rs b/kernel/driver/bus/pci/src/nodes.rs index 5cc33090..04a7357b 100644 --- a/kernel/driver/bus/pci/src/nodes.rs +++ b/kernel/driver/bus/pci/src/nodes.rs @@ -107,10 +107,13 @@ pub(crate) fn make_sysfs_object( for (capability, offset, _) in state.info.config_space.capability_iter() { write!(output, "{offset:04x}:").ok(); match capability { - PciCapabilityId::Msi => write!(output, "msi").ok(), - PciCapabilityId::MsiX => write!(output, "msix").ok(), - PciCapabilityId::VendorSpecific => write!(output, "vendor-specific").ok(), - PciCapabilityId::Unknown => write!(output, "unknown").ok(), + Some(PciCapabilityId::Msi) => write!(output, "msi").ok(), + Some(PciCapabilityId::MsiX) => write!(output, "msix").ok(), + Some(PciCapabilityId::VendorSpecific) => write!(output, "vendor-specific").ok(), + Some(PciCapabilityId::PowerManagement) => { + write!(output, "power-management").ok() + } + None => write!(output, "unknown").ok(), }; writeln!(output).ok(); } diff --git a/kernel/driver/bus/pci/src/space/mod.rs b/kernel/driver/bus/pci/src/space/mod.rs index d5d39fed..0c53156f 100644 --- a/kernel/driver/bus/pci/src/space/mod.rs +++ b/kernel/driver/bus/pci/src/space/mod.rs @@ -75,12 +75,12 @@ pub struct CapabilityIterator<'s, S: PciConfigurationSpace + ?Sized> { } impl Iterator for CapabilityIterator<'_, S> { - type Item = (PciCapabilityId, usize, usize); + type Item = (Option, usize, usize); fn next(&mut self) -> Option { let offset = self.current? & !0x3; - let id = unsafe { core::mem::transmute(self.space.read_u8(offset)) }; + let id = PciCapabilityId::try_from(self.space.read_u8(offset)).ok(); let len = self.space.read_u8(offset + 2); let next_pointer = self.space.read_u8(offset + 1); @@ -374,7 +374,7 @@ pub trait PciConfigurationSpace { /// Locates a capability within this configuration space fn capability(&self) -> Option> { self.capability_iter().find_map(|(id, offset, len)| { - if id == C::ID && C::check(self, offset, len) { + if id.map_or(false, |id| id == C::ID) && C::check(self, offset, len) { Some(C::data(self, offset, len)) } else { None diff --git a/kernel/driver/net/core/src/ethernet.rs b/kernel/driver/net/core/src/ethernet.rs index 9ac95c7c..4938ca26 100644 --- a/kernel/driver/net/core/src/ethernet.rs +++ b/kernel/driver/net/core/src/ethernet.rs @@ -1,4 +1,4 @@ -use core::mem::size_of; +use core::{fmt, mem::size_of}; use alloc::sync::Arc; use bytemuck::Pod; @@ -27,6 +27,37 @@ pub struct L2Packet { pub data: Arc>, } +/// Defines an Ethernet link speed +#[derive(Debug, Clone, Copy)] +pub enum EthernetSpeed { + /// 1Gbps link + Speed1000, + /// 100Mbps link + Speed100, + /// 10Mbps link + Speed10, + /// Link speed not available/unknown + Unknown, +} + +/// Defines whether an Ethernet link is capable of transmiting data both ways simultaneously +#[derive(Debug, Clone, Copy)] +pub enum Duplex { + /// Half-duplex link with multiplexed Tx and Rx + Half, + /// Full-duplex link capable of simultaneous Tx and Rx + Full, + /// Duplex mode not available/unknown + Unknown, +} + +/// Represents the state of an Ethernet link +#[derive(Debug, Clone, Copy)] +pub enum EthernetLinkState { + Up(EthernetSpeed, Duplex), + Down, +} + impl L2Packet { pub fn ethernet_frame(&self) -> &EthernetFrame { bytemuck::from_bytes( @@ -78,3 +109,39 @@ pub fn handle(packet: L2Packet) { } } } + +impl fmt::Display for EthernetSpeed { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let text = match self { + Self::Speed10 => "10Mbps", + Self::Speed100 => "100Mbps", + Self::Speed1000 => "1Gbps", + Self::Unknown => "N/A", + }; + f.write_str(text) + } +} + +impl fmt::Display for Duplex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let text = match self { + Self::Half => "half-duplex", + Self::Full => "full-duplex", + Self::Unknown => "N/A duplex mode", + }; + f.write_str(text) + } +} + +impl fmt::Display for EthernetLinkState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Up(speed, duplex) => { + write!(f, "up, speed {speed}, {duplex}") + } + Self::Down => { + write!(f, "down") + } + } + } +} diff --git a/kernel/driver/net/rtl81xx/src/lib.rs b/kernel/driver/net/rtl81xx/src/lib.rs index 1715f262..d6c1ca8c 100644 --- a/kernel/driver/net/rtl81xx/src/lib.rs +++ b/kernel/driver/net/rtl81xx/src/lib.rs @@ -4,6 +4,7 @@ use alloc::sync::Arc; use device_api::device::Device; use libk::error::Error; use rtl8139::Rtl8139; +use rtl8168::Rtl8168; use ygg_driver_pci::{ device::{PciDeviceInfo, PreferredInterruptMode}, PciBaseAddress, PciCommandRegister, PciConfigurationSpace, @@ -12,13 +13,28 @@ use ygg_driver_pci::{ extern crate alloc; pub mod rtl8139; +pub mod rtl8168; -pub fn probe_8169(_info: &PciDeviceInfo) -> Result, Error> { - todo!() +pub fn probe_8168(info: &PciDeviceInfo) -> Result, Error> { + let base = info + .config_space + .bar(2) + .and_then(PciBaseAddress::as_memory) + .ok_or(Error::InvalidArgument)?; + + // if let Some(power) = info.config_space.capability::() { + // power.set_device_power_state(DevicePowerState::D0); + // } + + // Enable MMIO + interrupts + bus mastering + info.set_command(true, true, false, true); + + let device = Rtl8168::new(base, info.clone())?; + Ok(Arc::new(device)) } pub fn probe_8139(info: &PciDeviceInfo) -> Result, Error> { - info.init_interrupts(PreferredInterruptMode::Msi)?; + info.init_interrupts(PreferredInterruptMode::Msi(false))?; // Enable MMIO + interrupts + bus mastering let mut command = info.config_space.command(); diff --git a/kernel/driver/net/rtl81xx/src/rtl8168.rs b/kernel/driver/net/rtl81xx/src/rtl8168.rs new file mode 100644 index 00000000..a380cdf7 --- /dev/null +++ b/kernel/driver/net/rtl81xx/src/rtl8168.rs @@ -0,0 +1,722 @@ +use core::{ + mem::{self, MaybeUninit}, + sync::atomic::{self, Ordering}, +}; + +use alloc::{sync::Arc, vec::Vec}; +use device_api::{device::Device, interrupt::InterruptHandler}; +use libk::error::Error; +use libk_mm::{ + address::{AsPhysicalAddress, PhysicalAddress}, + device::DeviceMemoryIo, + PageBox, +}; +use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; +use tock_registers::{ + interfaces::{ReadWriteable, Readable, Writeable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite, WriteOnly}, +}; +use ygg_driver_net_core::{ + ethernet::{Duplex, EthernetLinkState, EthernetSpeed}, + interface::{NetworkDevice, NetworkInterfaceType}, + Packet, +}; +use ygg_driver_pci::device::{PciDeviceInfo, PreferredInterruptMode}; +use yggdrasil_abi::{bitflags, net::MacAddress}; + +register_bitfields! { + u8, + CR [ + /// Software reset bit. Set by driver, cleared by device + RST OFFSET(4) NUMBITS(1) [], + /// Rx enable + RE OFFSET(3) NUMBITS(1) [], + /// Tx enable + TE OFFSET(2) NUMBITS(1) [], + ], + TPPOLL [ + HPQ OFFSET(7) NUMBITS(1) [], + NPQ OFFSET(6) NUMBITS(1) [], + FSWInt OFFSET(0) NUMBITS(1) [], + ], + PHYSTATUS [ + TXFLOW OFFSET(6) NUMBITS(1) [], + RXFLOW OFFSET(5) NUMBITS(1) [], + MF1000 OFFSET(4) NUMBITS(1) [], + M100 OFFSET(3) NUMBITS(1) [], + M10 OFFSET(2) NUMBITS(1) [], + LINKSTS OFFSET(1) NUMBITS(1) [], + FULLDUP OFFSET(0) NUMBITS(1) [], + ], +} + +register_bitfields! { + u16, + IMR_ISR [ + TIMEOUT OFFSET(14) NUMBITS(1) [], + FEMP OFFSET(9) NUMBITS(1) [], + SWINT OFFSET(8) NUMBITS(1) [], + TDU OFFSET(7) NUMBITS(1) [], + FOVW OFFSET(6) NUMBITS(1) [], + LINKCHG OFFSET(5) NUMBITS(1) [], + RDU OFFSET(4) NUMBITS(1) [], + TER OFFSET(3) NUMBITS(1) [], + TOK OFFSET(2) NUMBITS(1) [], + RER OFFSET(1) NUMBITS(1) [], + ROK OFFSET(0) NUMBITS(1) [], + ], + CPCR [ + /// (rtl8169sc) PCI endianness mode + ENDIAN OFFSET(9) NUMBITS(1) [ + Little = 0, + Big = 1, + ], + /// (no docs found) TBD + MACSTATDIS OFFSET(7) NUMBITS(1) [], + /// Rx VLAN de-tagging enable + RXVLAN OFFSET(6) NUMBITS(1) [], + /// Rx checksum offload enable + RXCHKSUM OFFSET(5) NUMBITS(1) [], + /// PCI dual address cycle enable + DAC OFFSET(4) NUMBITS(1) [], + /// PCI multiple read/write enable + MULRW OFFSET(3) NUMBITS(1) [], + + // Not documented, found in OpenBSD's re driver + /// C+ Rx mode enable + RXENB OFFSET(1) NUMBITS(1) [], + /// C+ Tx mode enable + TXENB OFFSET(0) NUMBITS(1) [], + ], +} + +register_bitfields! { + u32, + TCR [ + HWVERID0 OFFSET(28) NUMBITS(2) [], + HWVERID1 OFFSET(26) NUMBITS(1) [], + IFG OFFSET(24) NUMBITS(2) [], + HWVERID2 OFFSET(23) NUMBITS(1) [], + TX_NOCRC OFFSET(16) NUMBITS(1) [], + MXDMA OFFSET(8) NUMBITS(1) [ + Burst16 = 0b000, + Burst32 = 0b001, + Burst64 = 0b010, + Burst128 = 0b011, + Burst256 = 0b100, + Burst512 = 0b101, + Unlimited = 0b111, + ], + ], + RCR [ + RXFTH OFFSET(13) NUMBITS(3) [ + Threshold64 = 0b010, + Threshold128 = 0b011, + Threshold256 = 0b100, + Threshold512 = 0b101, + Threshold1024 = 0b110, + NoThreshold = 0b111, + ], + EARLYOFFV2 OFFSET(11) NUMBITS(1) [], + MXDMA OFFSET(8) NUMBITS(3) [ + Burst64 = 0b010, + Burst128 = 0b011, + Burst256 = 0b100, + Burst512 = 0b101, + Burst1024 = 0b110, + Unlimited = 0b111 + ], + R9356SEL OFFSET(6) NUMBITS(1) [], + AER OFFSET(5) NUMBITS(1) [], + AR OFFSET(4) NUMBITS(1) [], + AB OFFSET(3) NUMBITS(1) [], + AM OFFSET(2) NUMBITS(1) [], + APM OFFSET(1) NUMBITS(1) [], + AAP OFFSET(0) NUMBITS(1) [], + ], + PHYAR [ + FLAG OFFSET(31) NUMBITS(1) [ + Read = 0, + Write = 1, + ], + REGADDR OFFSET(16) NUMBITS(5) [], + DATA OFFSET(0) NUMBITS(16) [], + ], +} + +register_structs! { + #[allow(non_snake_case)] + Regs { + (0x0000 => IDRn: [ReadWrite; 2]), + (0x0008 => MARn: [ReadWrite; 2]), + (0x0010 => DTCCR: ReadWrite), + (0x0018 => _0), + (0x0020 => TNPDS: [ReadWrite; 2]), + (0x0028 => THPDS: [ReadWrite; 2]), + (0x0030 => _1), + (0x0037 => CR: ReadWrite), + (0x0038 => TPPOLL: WriteOnly), + (0x0039 => _2), + (0x003C => IMR: ReadWrite), + (0x003E => ISR: ReadWrite), + (0x0040 => TCR: ReadWrite), + (0x0044 => RCR: ReadWrite), + (0x0048 => TCTR: ReadWrite), + (0x004C => MPKT: ReadWrite), + (0x0050 => R9346CR: ReadWrite), + (0x0051 => CONFIG0: ReadWrite), + (0x0052 => CONFIG1: ReadWrite), + (0x0053 => CONFIG2: ReadWrite), + (0x0054 => CONFIG3: ReadWrite), + (0x0055 => CONFIG4: ReadWrite), + (0x0056 => CONFIG5: ReadWrite), + (0x0057 => _4), + (0x0058 => TIMERINT: ReadWrite), + (0x005C => _5), + (0x0060 => PHYAR: ReadWrite), + (0x0064 => _6), + (0x006C => PHYSTATUS: ReadOnly), + (0x006D => _7), + (0x0084 => WAKEUPn: [ReadWrite; 16]), + (0x00C4 => CRCn: [ReadWrite; 5]), + (0x00CE => _8), + (0x00DA => RMS: ReadWrite), + (0x00DC => _9), + (0x00E0 => CPCR: ReadWrite), + (0x00E2 => _10), + (0x00E4 => RDSAR: [ReadWrite; 2]), + (0x00EC => MTPS: ReadWrite), + (0x00ED => _11), + (0x00F0 => MISC: ReadWrite), + (0x00F4 => _12), + (0x0100 => @END), + } +} + +bitflags! { + struct ChipFlags: u32 { + const MACSTAT: bit 0; + const NEED_PHY_RESET: bit 1; + const RXDV_GATED: bit 2; + const EARLYOFFV2: bit 3; + } +} + +#[derive(Clone, Copy, PartialEq, Debug)] +#[allow(non_camel_case_types)] +enum Revision { + rtl8168gu, + rtl8168h, + other, +} + +#[repr(C)] +struct Descriptor { + cmd: u32, + vlan_cmd: u32, + address: PhysicalAddress, +} + +struct RxRing { + entries: PageBox<[Descriptor]>, + buffers: Vec]>>, + rd: usize, +} + +struct TxRing { + entries: PageBox<[Descriptor]>, + buffers: Vec>>, + wr: usize, + rd: usize, +} + +pub struct Rtl8168 { + regs: IrqSafeSpinlock>, + mac: MacAddress, + pci: PciDeviceInfo, + + nic: OneTimeInit, + rx: OneTimeInit>, + tx: OneTimeInit>, +} + +impl RxRing { + pub fn with_capacity(capacity: usize) -> Result { + let buffers = (0..capacity) + .map(|_| PageBox::new_uninit_slice(4096)) + .collect::, _>>()?; + let entries = PageBox::new_slice_with( + |i| { + Descriptor::new_rx( + unsafe { buffers[i].as_physical_address() }, + i == capacity - 1, + ) + }, + capacity, + )?; + unsafe { core::arch::asm!("wbinvd") }; + Ok(Self { + entries, + buffers, + rd: 0, + }) + } + + pub fn consume)>(&mut self, handler: F) -> Result { + let mut count = 0; + loop { + let index = self.rd % self.entries.len(); + let entry = &self.entries[index]; + + if entry.is_host_owned() { + let new_buffer = PageBox::new_uninit_slice(4096)?; + let new_buffer_address = unsafe { new_buffer.as_physical_address() }; + let buffer = mem::replace(&mut self.buffers[index], new_buffer); + let buffer = unsafe { buffer.assume_init_slice() }; + handler(buffer); + + self.entries[index].setup_rx(new_buffer_address); + + self.rd = self.rd.wrapping_add(1); + count += 1; + } else { + break; + } + } + Ok(count) + } + + pub fn base_address(&self) -> PhysicalAddress { + unsafe { self.entries.as_physical_address() } + } +} + +impl TxRing { + pub fn with_capacity(capacity: usize) -> Result { + let entries = + PageBox::new_slice_with(|i| Descriptor::empty_tx(i == capacity - 1), capacity)?; + let buffers = (0..capacity).map(|_| None).collect(); + + Ok(Self { + entries, + buffers, + wr: 0, + rd: 0, + }) + } + + pub fn is_full(&self) -> bool { + self.wr.wrapping_add(1) % self.entries.len() == self.rd % self.entries.len() + } + + pub fn push(&mut self, packet: PageBox<[u8]>) -> Result<(), Error> { + let packet_base = unsafe { packet.as_physical_address() }; + let packet_size = packet.len(); + + // TODO packet size checks + + if self.is_full() { + log::warn!("rtl81xx: tx ring full: wr={}, rd={}", self.wr, self.rd); + return Err(Error::WouldBlock); + } + + let index = self.wr % self.entries.len(); + self.buffers[index] = Some(packet); + self.entries[index].setup_tx(packet_base, packet_size); + + self.wr = self.wr.wrapping_add(1); + + Ok(()) + } + + pub fn consume(&mut self) -> Result { + let mut count = 0; + loop { + let index = self.rd % self.entries.len(); + let entry = &mut self.entries[index]; + + if self.rd != self.wr && entry.is_host_owned() { + self.rd = self.rd.wrapping_add(1); + count += 1; + } else { + break; + } + } + Ok(count) + } + + pub fn base_address(&self) -> PhysicalAddress { + unsafe { self.entries.as_physical_address() } + } +} + +impl Descriptor { + // Descriptor owned by DMA + const CMD_OWN: u32 = 1 << 31; + // Last descriptor in the ring + const CMD_END: u32 = 1 << 30; + // Last segment of a packet + const CMD_LS: u32 = 1 << 28; + // First segment of a packet + const CMD_FS: u32 = 1 << 29; + + pub fn new_rx(buffer: PhysicalAddress, last: bool) -> Self { + let mut cmd = Self::CMD_OWN | 0x1000; + if last { + cmd |= Self::CMD_END; + } + Self { + cmd, + vlan_cmd: 0, + address: buffer, + } + } + + pub fn empty_tx(last: bool) -> Self { + let cmd = if last { Self::CMD_END } else { 0 }; + Self { + cmd, + vlan_cmd: 0, + address: PhysicalAddress::ZERO, + } + } + + pub fn setup_rx(&mut self, buffer: PhysicalAddress) { + let cmd = self.cmd; + self.address = buffer; + self.vlan_cmd = 0; + unsafe { + atomic::fence(Ordering::Release); + core::arch::asm!("wbinvd"); + core::ptr::write_volatile(&mut self.cmd, cmd | Self::CMD_OWN); + } + } + + pub fn setup_tx(&mut self, buffer: PhysicalAddress, size: usize) { + let mut cmd = self.cmd; + cmd |= Self::CMD_OWN | Self::CMD_FS | Self::CMD_LS | (size as u32); + self.address = buffer; + self.vlan_cmd = 0; + unsafe { + atomic::fence(Ordering::Release); + core::arch::asm!("wbinvd"); + core::ptr::write_volatile(&mut self.cmd, cmd); + } + } + + pub fn is_host_owned(&self) -> bool { + self.cmd & Self::CMD_OWN == 0 + } +} + +impl Regs { + const TCR_REVISION_MASK: u32 = 0x7C800000; + + pub fn gmii_write(&self, reg: u8, value: u16, mut timeout: u64) -> Result<(), Error> { + self.PHYAR.write( + PHYAR::REGADDR.val(reg as u32) + PHYAR::DATA.val(value as u32) + PHYAR::FLAG::Write, + ); + while timeout > 0 && self.PHYAR.matches_all(PHYAR::FLAG::SET) { + core::hint::spin_loop(); + timeout -= 1; + } + if timeout == 0 { + Err(Error::TimedOut) + } else { + Ok(()) + } + } + + #[allow(unused)] + pub fn gmii_read(&self, reg: u8, mut timeout: u64) -> Result { + self.PHYAR + .write(PHYAR::REGADDR.val(reg as u32) + PHYAR::FLAG::Read); + + loop { + if timeout == 0 { + return Err(Error::TimedOut); + } + + let status = self.PHYAR.extract(); + if status.matches_all(PHYAR::FLAG::SET) { + return Ok(status.read(PHYAR::DATA) as u16); + } + + core::hint::spin_loop(); + timeout -= 1; + } + } + + pub fn get_link_state(&self) -> EthernetLinkState { + let phystatus = self.PHYSTATUS.extract(); + if phystatus.matches_all(PHYSTATUS::LINKSTS::SET) { + let duplex = if phystatus.matches_all(PHYSTATUS::FULLDUP::SET) { + Duplex::Full + } else { + Duplex::Half + }; + let (speed, duplex) = if phystatus.matches_all(PHYSTATUS::MF1000::SET) { + // 1000MF is always Full-Duplex + (EthernetSpeed::Speed1000, Duplex::Full) + } else if phystatus.matches_all(PHYSTATUS::M100::SET) { + (EthernetSpeed::Speed100, duplex) + } else if phystatus.matches_all(PHYSTATUS::M10::SET) { + (EthernetSpeed::Speed10, duplex) + } else { + (EthernetSpeed::Unknown, duplex) + }; + + EthernetLinkState::Up(speed, duplex) + } else { + EthernetLinkState::Down + } + } + + pub fn get_chip_revision(&self) -> Revision { + let rev = self.TCR.get() & Self::TCR_REVISION_MASK; + match rev { + 0x50800000 => Revision::rtl8168gu, + 0x54000000 => Revision::rtl8168h, + _ => Revision::other, + } + } + + pub fn reset_device(&self, mut timeout: u64) -> Result<(), Error> { + self.CR.write(CR::RST::SET); + + while timeout > 0 && self.CR.matches_all(CR::RST::SET) { + core::hint::spin_loop(); + timeout -= 1; + } + + if timeout == 0 { + Err(Error::TimedOut) + } else { + Ok(()) + } + } + + pub fn reset_phy(&self, timeout: u64) -> Result<(), Error> { + // Set the reset bit in bmcr + self.gmii_write(0x00, 1 << 15, timeout)?; + for _ in 0..timeout { + core::hint::spin_loop(); + } + // Disable power off mode + start auto-negotiation + self.gmii_write(0x00, 1 << 12, timeout)?; + for _ in 0..timeout { + core::hint::spin_loop(); + } + + self.gmii_write(0x1F, 0x00, timeout)?; + self.gmii_write(0x0E, 0x00, timeout)?; + + Ok(()) + } + + // #[inline] + // pub fn lock_config(&self) { + // self.R9346CR.set(0x00); + // } + + // #[inline] + // pub fn unlock_config(&self) { + // self.R9346CR.set(0xC0); + // } +} + +impl Rtl8168 { + pub fn new(base: PhysicalAddress, info: PciDeviceInfo) -> Result { + let regs = unsafe { DeviceMemoryIo::::map(base, Default::default()) }?; + let mac0 = regs.IDRn[0].get().to_le_bytes(); + let mac1 = regs.IDRn[1].get().to_le_bytes(); + let mac = MacAddress::from([mac0[0], mac0[1], mac0[2], mac0[3], mac1[0], mac1[1]]); + Ok(Self { + regs: IrqSafeSpinlock::new(regs), + mac, + pci: info, + + nic: OneTimeInit::new(), + rx: OneTimeInit::new(), + tx: OneTimeInit::new(), + }) + } +} + +impl InterruptHandler for Rtl8168 { + fn handle_irq(self: Arc, _vector: Option) -> bool { + let regs = self.regs.lock(); + let status = regs.ISR.extract(); + + if status.get() == 0 { + return false; + } + regs.ISR.set(status.get()); + + let mut any = false; + if status.matches_all(IMR_ISR::LINKCHG::SET) { + let state = regs.get_link_state(); + log::info!("rtl8168: link is {state}"); + any = true; + } + if status.matches_all(IMR_ISR::ROK::SET) { + let mut rx = self.rx.get().lock(); + let nic = *self.nic.get(); + let count = rx + .consume(|buffer| { + // TODO add packet len hint to packets + let packet = Packet::new(buffer, 0, nic); + ygg_driver_net_core::receive_packet(packet).ok(); + }) + .unwrap_or(0); + + any |= count != 0; + } + if status.matches_all(IMR_ISR::TOK::SET) { + let mut tx = self.tx.get().lock(); + let count = tx.consume().unwrap_or(0); + any |= count != 0; + } + if status.matches_all(IMR_ISR::RDU::SET) { + log::info!("rtl8168: rdu"); + any |= true; + } + + if !any { + log::warn!("rtl8168: possibly unhandled IRQ, ISR={:#x}", status.get()); + } + + any + } +} + +impl Device for Rtl8168 { + unsafe fn init(self: Arc) -> Result<(), Error> { + log::info!("Initialize rtl8168"); + log::info!("MAC: {}", self.mac); + + let rx_ring = RxRing::with_capacity(256)?; + let tx_ring = TxRing::with_capacity(256)?; + let rx_ring_base = rx_ring.base_address().into_u64(); + let tx_ring_base = tx_ring.base_address().into_u64(); + + let regs = self.regs.lock(); + let hwrev = regs.get_chip_revision(); + + log::info!("Revision: {:?}", hwrev); + let flags = hwrev.flags(); + + // Perform software reset + regs.reset_device(10000000) + .inspect_err(|_| log::warn!("rtl81xx: reset timed out"))?; + + // Enable C+ mode for Rx/Tx + let mut cpcr = CPCR::TXENB::SET + CPCR::MULRW::SET + CPCR::RXCHKSUM::SET; + if flags.contains(ChipFlags::MACSTAT) { + cpcr += CPCR::MACSTATDIS::SET; + } else { + cpcr += CPCR::RXENB::SET; + } + regs.CPCR.write(cpcr); + + // Reset the PHY + if flags.contains(ChipFlags::NEED_PHY_RESET) { + regs.reset_phy(10000000) + .inspect_err(|_| log::warn!("rtl81xx: PHY reset timed out"))?; + } + + regs.RDSAR[1].set((rx_ring_base >> 32) as u32); + regs.RDSAR[0].set(rx_ring_base as u32); + regs.TNPDS[1].set((tx_ring_base >> 32) as u32); + regs.TNPDS[0].set(tx_ring_base as u32); + + if flags.contains(ChipFlags::RXDV_GATED) { + regs.MISC.set(regs.MISC.get() & !0x80000); + } + + log::info!("rx_ring_base = {rx_ring_base:#x}"); + + unsafe { core::arch::asm!("wbinvd") }; + + // Setup Tx + regs.TCR.modify(TCR::MXDMA::Unlimited); + // Setup Rx + let mut rcr = RCR::MXDMA::Unlimited + + RCR::RXFTH::NoThreshold + + RCR::AB::SET + + RCR::AM::SET + + RCR::APM::SET; + if flags.contains(ChipFlags::EARLYOFFV2) { + rcr += RCR::EARLYOFFV2::SET; + } + regs.RCR.write(rcr); + + // Enable Rx/Tx + regs.CR.write(CR::RE::SET + CR::TE::SET); + + // Setup interrupts + regs.IMR.set(0xFFFF); + regs.ISR.set(0xFFFF); + + // Clear missed packet counter (?) + regs.MPKT.set(0); + + regs.MTPS.set(31); + regs.RMS.set(0x1FFF); + + regs.CONFIG1.set(regs.CONFIG1.get() | 0x20); + + self.rx.init(IrqSafeSpinlock::new(rx_ring)); + self.tx.init(IrqSafeSpinlock::new(tx_ring)); + + // Bind IRQ + self.pci + .init_interrupts(PreferredInterruptMode::Msi(false))?; + self.pci.map_interrupt(Default::default(), self.clone())?; + + let interface = + ygg_driver_net_core::register_interface(NetworkInterfaceType::Ethernet, self.clone()); + self.nic.init(interface.id()); + + Ok(()) + } + + fn display_name(&self) -> &str { + "Realtek RTL8111/8168 Gigabit Ethernet Controller" + } +} + +impl NetworkDevice for Rtl8168 { + fn transmit(&self, packet: PageBox<[u8]>) -> Result<(), Error> { + let mut tx = self.tx.get().lock(); + let regs = self.regs.lock(); + + tx.push(packet)?; + regs.TPPOLL.write(TPPOLL::NPQ::SET); + + Ok(()) + } + + fn packet_prefix_size(&self) -> usize { + 0 + } + + fn read_hardware_address(&self) -> MacAddress { + self.mac + } +} + +impl Revision { + fn flags(&self) -> ChipFlags { + match self { + Self::rtl8168h | Self::rtl8168gu => { + ChipFlags::NEED_PHY_RESET + | ChipFlags::MACSTAT + | ChipFlags::RXDV_GATED + | ChipFlags::EARLYOFFV2 + } + Self::other => ChipFlags::empty(), + } + } +} diff --git a/kernel/driver/usb/xhci/src/lib.rs b/kernel/driver/usb/xhci/src/lib.rs index 00a5d234..4a3d4267 100644 --- a/kernel/driver/usb/xhci/src/lib.rs +++ b/kernel/driver/usb/xhci/src/lib.rs @@ -103,7 +103,7 @@ pub fn probe(info: &PciDeviceInfo) -> Result, Error> { let regs = unsafe { xhci_lib::Registers::new(bar0.try_into_usize().unwrap(), Mapper::new()) }; let xhci = Arc::new(Xhci::new(regs)?); - info.init_interrupts(PreferredInterruptMode::Msi)?; + info.init_interrupts(PreferredInterruptMode::Msi(true))?; info.map_interrupt(InterruptAffinity::Any, xhci.clone())?; Ok(xhci) diff --git a/kernel/driver/virtio/net/src/lib.rs b/kernel/driver/virtio/net/src/lib.rs index a5ca9c0f..97b7ffe5 100644 --- a/kernel/driver/virtio/net/src/lib.rs +++ b/kernel/driver/virtio/net/src/lib.rs @@ -176,7 +176,7 @@ impl VirtioNet { transmit_count: usize, ) -> Result<(), Error> { let receive_vector = if let Some(pci) = self.pci_device_info.as_ref() { - pci.init_interrupts(PreferredInterruptMode::Msi)?; + pci.init_interrupts(PreferredInterruptMode::Msi(true))?; let info = pci.map_interrupt(InterruptAffinity::Any, self.clone())?; info.map(|info| info.vector as u16) diff --git a/kernel/src/arch/x86/mod.rs b/kernel/src/arch/x86/mod.rs index 363dd214..c76ce0bf 100644 --- a/kernel/src/arch/x86/mod.rs +++ b/kernel/src/arch/x86/mod.rs @@ -70,13 +70,13 @@ pub fn register_pci_drivers() { 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_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, @@ -96,10 +96,10 @@ pub fn register_pci_drivers() { ygg_driver_net_rtl81xx::probe_8139, ); ygg_driver_pci::register_vendor_driver( - "Realtek RTL8169/8110 Gigabit Ethernet", + "Realtek RTL8168/8111 Gigabit Ethernet", 0x10EC, - 0x8169, - ygg_driver_net_rtl81xx::probe_8169, + 0x8168, + ygg_driver_net_rtl81xx::probe_8168, ); } diff --git a/kernel/src/arch/x86_64/apic/ioapic.rs b/kernel/src/arch/x86_64/apic/ioapic.rs index 675e53a6..425fc648 100644 --- a/kernel/src/arch/x86_64/apic/ioapic.rs +++ b/kernel/src/arch/x86_64/apic/ioapic.rs @@ -64,7 +64,7 @@ struct Inner { pub struct IoApic { inner: IrqSafeSpinlock, isa_redirections: [Option; 16], - table: IrqSafeRwLock>, // table: IrqSafeSpinlock>, + table: IrqSafeRwLock>, } impl Regs { diff --git a/kernel/src/arch/x86_64/apic/local.rs b/kernel/src/arch/x86_64/apic/local.rs index abf1f7f7..e862a71d 100644 --- a/kernel/src/arch/x86_64/apic/local.rs +++ b/kernel/src/arch/x86_64/apic/local.rs @@ -259,7 +259,7 @@ impl MessageInterruptController for LocalApic { ); let value = 32 + APIC_MSI_OFFSET + i as u32; - let address = Self::base().into_usize() | ((self.id as usize) << 12); + let address = 0xFEE00000 | ((self.id as usize) << 12); *msi = MsiInfo { address,