net: implement rtl8168 driver

This commit is contained in:
Mark Poliakov 2025-01-29 11:33:54 +02:00
parent 50a760985b
commit 2f46a36255
18 changed files with 1110 additions and 90 deletions

15
Cargo.lock generated
View File

@ -57,7 +57,7 @@ dependencies = [
[[package]] [[package]]
name = "acpi-system" name = "acpi-system"
version = "0.1.0" 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 = [ dependencies = [
"acpi", "acpi",
"aml", "aml",
@ -1838,9 +1838,9 @@ dependencies = [
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.18" version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
[[package]] [[package]]
name = "same-file" name = "same-file"
@ -2229,9 +2229,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.15" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
@ -2531,9 +2531,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.6.24" version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -2734,6 +2734,7 @@ dependencies = [
"acpi", "acpi",
"bitflags 2.8.0", "bitflags 2.8.0",
"device-api", "device-api",
"kernel-arch-x86",
"libk", "libk",
"libk-mm", "libk-mm",
"libk-util", "libk-util",

View File

@ -202,7 +202,7 @@ pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER; cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER;
info.config_space.set_command(cmd.bits()); 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) // // TODO support regular PCI interrupts (ACPI dependency)
// let Some(mut msi) = info.config_space.capability::<MsiCapability>() else { // let Some(mut msi) = info.config_space.capability::<MsiCapability>() else {

View File

@ -428,7 +428,7 @@ pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
.as_memory() .as_memory()
.expect("Expected a memory BAR0"); .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()); let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command());
cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO); cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO);

View File

@ -18,6 +18,7 @@ tock-registers.workspace = true
[target.'cfg(target_arch = "x86_64")'.dependencies] [target.'cfg(target_arch = "x86_64")'.dependencies]
ygg_driver_acpi.path = "../../acpi" ygg_driver_acpi.path = "../../acpi"
acpi.workspace = true acpi.workspace = true
kernel-arch-x86.workspace = true
[lints] [lints]
workspace = true workspace = true

View File

@ -1,9 +1,12 @@
//! PCI capability structures and queries //! PCI capability structures and queries
use core::mem::offset_of;
use alloc::{sync::Arc, vec, vec::Vec}; use alloc::{sync::Arc, vec, vec::Vec};
use device_api::interrupt::{ use device_api::interrupt::{
InterruptAffinity, InterruptHandler, MessageInterruptController, MsiInfo, InterruptAffinity, InterruptHandler, MessageInterruptController, MsiInfo,
}; };
use kernel_arch_x86::intrinsics;
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut}; use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
use tock_registers::{ use tock_registers::{
interfaces::{Readable, Writeable}, interfaces::{Readable, Writeable},
@ -11,6 +14,8 @@ use tock_registers::{
}; };
use yggdrasil_abi::error::Error; use yggdrasil_abi::error::Error;
use crate::PciBaseAddress;
use super::{PciCapability, PciCapabilityId, PciConfigurationSpace}; use super::{PciCapability, PciCapabilityId, PciConfigurationSpace};
pub trait VirtioCapabilityData<'s, S: PciConfigurationSpace + ?Sized + 's>: Sized { 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>; type Output<'a, S: PciConfigurationSpace + ?Sized + 'a>: VirtioCapabilityData<'a, S>;
} }
/// Power management capability entry
pub struct PowerManagementCapability;
/// MSI-X capability query /// MSI-X capability query
pub struct MsiXCapability; pub struct MsiXCapability;
@ -57,6 +65,15 @@ pub struct VirtioNotifyConfigCapability;
/// VirtIO interrupt status /// VirtIO interrupt status
pub struct VirtioInterruptStatusCapability; 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 /// Represents an entry in MSI-X vector table
#[repr(C)] #[repr(C)]
pub struct MsiXEntry { pub struct MsiXEntry {
@ -68,8 +85,20 @@ pub struct MsiXEntry {
pub control: ReadWrite<u32>, pub control: ReadWrite<u32>,
} }
enum MsiXVectorTableAccess<'a> {
Memory(DeviceMemoryIoMut<'a, [MsiXEntry]>),
Io(u16),
}
pub struct MsiXVectorTable<'a> { 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 /// MSI-X capability data structure
@ -122,6 +151,19 @@ impl<T: VirtioCapability> 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 { impl PciCapability for MsiXCapability {
const ID: PciCapabilityId = PciCapabilityId::MsiX; const ID: PciCapabilityId = PciCapabilityId::MsiX;
type CapabilityData<'a, S: PciConfigurationSpace + ?Sized + 'a> = MsiXData<'a, S>; 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> { impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiXData<'s, S> {
// TODO use pending bits as well // TODO use pending bits as well
/// Maps and returns the vector table associated with the device's MSI-X capability /// 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 { let Some(base) = self.space.bar(bir) else {
return Err(Error::DoesNotExist); 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)); match base {
PciBaseAddress::Memory32(mem32) => unsafe {
unsafe { MsiXVectorTable::from_raw_parts(base.add(table_offset), table_size) } 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 /// 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::<MsiXEntry>() + 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::<MsiXEntry>()) 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::<MsiXEntry>() + 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::<MsiXEntry>() + offset_of!(MsiXEntry, control)) as u16;
intrinsics::outl(a, value)
},
Self::Memory(vectors) => vectors[vector].control.set(value),
}
}
}
impl MsiXVectorTable<'_> { impl MsiXVectorTable<'_> {
unsafe fn from_raw_parts(base: PhysicalAddress, len: usize) -> Result<Self, Error> { unsafe fn memory_from_raw_parts(base: PhysicalAddress, len: usize) -> Result<Self, Error> {
let vectors = DeviceMemoryIoMut::map_slice(base, len, Default::default())?; 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<Self, Error> {
Ok(Self {
access: MsiXVectorTableAccess::Io(base),
len,
})
} }
pub fn mask_all(&mut self) { pub fn mask_all(&mut self) {
for vector in self.vectors.iter_mut() { for i in 0..self.len {
vector.set_masked(true); self.access.set_vector_masked(i, true);
} }
} }
@ -324,26 +478,15 @@ impl MsiXVectorTable<'_> {
for (i, info) in range.iter().enumerate() { for (i, info) in range.iter().enumerate() {
let index = i + start; let index = i + start;
self.vectors[index].address.set(info.address as _); self.access.write_address(index, info.address as _);
self.vectors[index].data.set(info.value); self.access.write_data(index, info.value);
self.vectors[index].set_masked(false); self.access.set_vector_masked(index, false);
} }
Ok(range) 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> { impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiData<'s, S> {
pub fn register<C: MessageInterruptController + ?Sized>( pub fn register<C: MessageInterruptController + ?Sized>(
&mut self, &mut self,

View File

@ -11,7 +11,7 @@ use yggdrasil_abi::error::Error;
use crate::{ use crate::{
capability::{MsiCapability, MsiXCapability, MsiXVectorTable}, capability::{MsiCapability, MsiXCapability, MsiXVectorTable},
PciAddress, PciConfigSpace, PciConfigurationSpace, PciSegmentInfo, PciAddress, PciCommandRegister, PciConfigSpace, PciConfigurationSpace, PciSegmentInfo,
}; };
/// Describes a PCI device /// Describes a PCI device
@ -53,7 +53,7 @@ pub enum PciInterruptPin {
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum PreferredInterruptMode { pub enum PreferredInterruptMode {
Msi, Msi(bool),
Legacy, Legacy,
} }
@ -85,6 +85,7 @@ pub enum PciMatch {
} }
pub struct PciDriver { pub struct PciDriver {
#[allow(unused)]
pub(crate) name: &'static str, pub(crate) name: &'static str,
pub(crate) check: PciMatch, pub(crate) check: PciMatch,
pub(crate) probe: fn(&PciDeviceInfo) -> Result<Arc<dyn Device>, Error>, pub(crate) probe: fn(&PciDeviceInfo) -> Result<Arc<dyn Device>, Error>,
@ -98,22 +99,70 @@ pub struct PciBusDevice {
} }
impl PciDeviceInfo { 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> { pub fn init_interrupts(&self, preferred_mode: PreferredInterruptMode) -> Result<(), Error> {
self.interrupt_config self.interrupt_config
.try_init_with(|| { .try_init_with(|| {
let configured_mode = let configured_mode = if self.segment.has_msi
if self.segment.has_msi && preferred_mode == PreferredInterruptMode::Msi { && let PreferredInterruptMode::Msi(want_msix) = preferred_mode
if let Some(mut msix) = self.config_space.capability::<MsiXCapability>() { {
let mut vt = msix.vector_table().unwrap(); // Try MSI-X first
let mut result = None;
if want_msix
&& let Some(mut msix) = self.config_space.capability::<MsiXCapability>()
{
if let Ok(mut vt) = msix.vector_table() {
vt.mask_all(); vt.mask_all();
msix.set_function_mask(false); msix.set_function_mask(false);
msix.set_enabled(true); msix.set_enabled(true);
ConfiguredInterruptMode::MsiX(vt) result = Some(ConfiguredInterruptMode::MsiX(vt));
} else if self.config_space.capability::<MsiCapability>().is_some() { }
ConfiguredInterruptMode::Msi }
// Then try MSI
if result.is_none() && self.config_space.capability::<MsiCapability>().is_some()
{
result = Some(ConfiguredInterruptMode::Msi)
}
// And then fall back to legacy
if let Some(result) = result {
result
} else { } else {
self.legacy_interrupt_mode() self.legacy_interrupt_mode()
} }

View File

@ -33,6 +33,14 @@ impl PciInterruptMap {
interrupt.address.function as u16, interrupt.address.function as u16,
aml_pin, 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)?; .ok_or(Error::DoesNotExist)?;
let trigger = match aml_route.trigger { let trigger = match aml_route.trigger {

View File

@ -1,5 +1,6 @@
//! PCI/PCIe bus interfaces //! PCI/PCIe bus interfaces
#![no_std] #![no_std]
#![feature(let_chains)]
#![allow(clippy::missing_transmute_annotations)] #![allow(clippy::missing_transmute_annotations)]
extern crate alloc; extern crate alloc;
@ -18,7 +19,7 @@ use libk::fs::sysfs::{self, object::KObject};
use libk_mm::address::PhysicalAddress; use libk_mm::address::PhysicalAddress;
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use space::legacy; use space::legacy;
use yggdrasil_abi::error::Error; use yggdrasil_abi::{error::Error, primitive_enum};
pub mod capability; pub mod capability;
pub mod device; pub mod device;
@ -34,6 +35,7 @@ pub use space::{
bitflags! { bitflags! {
/// Command register of the PCI configuration space /// Command register of the PCI configuration space
#[derive(PartialEq, Clone, Copy)]
pub struct PciCommandRegister: u16 { pub struct PciCommandRegister: u16 {
/// If set, I/O access to the device is enabled /// If set, I/O access to the device is enabled
const ENABLE_IO = 1 << 0; const ENABLE_IO = 1 << 0;
@ -78,20 +80,28 @@ pub enum PciBaseAddress {
Io(u16), Io(u16),
} }
/// Unique ID assigned to PCI capability structures primitive_enum! {
#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum PciCapabilityId: u8 {
#[non_exhaustive] PowerManagement = 0x01,
#[repr(u8)]
pub enum PciCapabilityId {
/// MSI (32-bit or 64-bit)
Msi = 0x05, Msi = 0x05,
/// Vendor-specific capability
VendorSpecific = 0x09, VendorSpecific = 0x09,
/// MSI-X
MsiX = 0x11, MsiX = 0x11,
/// Unknown capability missing from this list
Unknown,
} }
}
// /// 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 /// Interface used for querying PCI capabilities
#[allow(unused)] #[allow(unused)]
@ -429,9 +439,9 @@ impl PciBusManager {
/// Walks the bus device list and calls init/init_irq functions on any devices with associated /// Walks the bus device list and calls init/init_irq functions on any devices with associated
/// drivers /// drivers
pub fn setup_bus_devices() -> Result<(), Error> { pub fn setup_bus_devices() -> Result<(), Error> {
log::info!("Setting up bus devices"); // log::info!("Setting up bus devices");
Self::walk_bus_devices(|device| { Self::walk_bus_devices(|device| {
log::info!("Set up {}", device.info.address); // log::info!("Set up {}", device.info.address);
setup_bus_device(device)?; setup_bus_device(device)?;
Ok(true) Ok(true)
}) })
@ -610,7 +620,7 @@ fn setup_bus_device(device: &mut PciBusDevice) -> Result<(), Error> {
for driver in drivers.iter() { for driver in drivers.iter() {
if driver.check.check_device(&device.info) { if driver.check.check_device(&device.info) {
// TODO add the device to the bus // TODO add the device to the bus
log::debug!(" -> {:?}", driver.name); // log::debug!(" -> {:?}", driver.name);
let instance = (driver.probe)(&device.info)?; let instance = (driver.probe)(&device.info)?;
unsafe { instance.clone().init() }?; unsafe { instance.clone().init() }?;

View File

@ -107,10 +107,13 @@ pub(crate) fn make_sysfs_object(
for (capability, offset, _) in state.info.config_space.capability_iter() { for (capability, offset, _) in state.info.config_space.capability_iter() {
write!(output, "{offset:04x}:").ok(); write!(output, "{offset:04x}:").ok();
match capability { match capability {
PciCapabilityId::Msi => write!(output, "msi").ok(), Some(PciCapabilityId::Msi) => write!(output, "msi").ok(),
PciCapabilityId::MsiX => write!(output, "msix").ok(), Some(PciCapabilityId::MsiX) => write!(output, "msix").ok(),
PciCapabilityId::VendorSpecific => write!(output, "vendor-specific").ok(), Some(PciCapabilityId::VendorSpecific) => write!(output, "vendor-specific").ok(),
PciCapabilityId::Unknown => write!(output, "unknown").ok(), Some(PciCapabilityId::PowerManagement) => {
write!(output, "power-management").ok()
}
None => write!(output, "unknown").ok(),
}; };
writeln!(output).ok(); writeln!(output).ok();
} }

View File

@ -75,12 +75,12 @@ pub struct CapabilityIterator<'s, S: PciConfigurationSpace + ?Sized> {
} }
impl<S: PciConfigurationSpace + ?Sized> Iterator for CapabilityIterator<'_, S> { impl<S: PciConfigurationSpace + ?Sized> Iterator for CapabilityIterator<'_, S> {
type Item = (PciCapabilityId, usize, usize); type Item = (Option<PciCapabilityId>, usize, usize);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let offset = self.current? & !0x3; 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 len = self.space.read_u8(offset + 2);
let next_pointer = self.space.read_u8(offset + 1); let next_pointer = self.space.read_u8(offset + 1);
@ -374,7 +374,7 @@ pub trait PciConfigurationSpace {
/// Locates a capability within this configuration space /// Locates a capability within this configuration space
fn capability<C: PciCapability>(&self) -> Option<C::CapabilityData<'_, Self>> { fn capability<C: PciCapability>(&self) -> Option<C::CapabilityData<'_, Self>> {
self.capability_iter().find_map(|(id, offset, len)| { 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)) Some(C::data(self, offset, len))
} else { } else {
None None

View File

@ -1,4 +1,4 @@
use core::mem::size_of; use core::{fmt, mem::size_of};
use alloc::sync::Arc; use alloc::sync::Arc;
use bytemuck::Pod; use bytemuck::Pod;
@ -27,6 +27,37 @@ pub struct L2Packet {
pub data: Arc<PageBox<[u8]>>, pub data: Arc<PageBox<[u8]>>,
} }
/// 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 { impl L2Packet {
pub fn ethernet_frame(&self) -> &EthernetFrame { pub fn ethernet_frame(&self) -> &EthernetFrame {
bytemuck::from_bytes( 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")
}
}
}
}

View File

@ -4,6 +4,7 @@ use alloc::sync::Arc;
use device_api::device::Device; use device_api::device::Device;
use libk::error::Error; use libk::error::Error;
use rtl8139::Rtl8139; use rtl8139::Rtl8139;
use rtl8168::Rtl8168;
use ygg_driver_pci::{ use ygg_driver_pci::{
device::{PciDeviceInfo, PreferredInterruptMode}, device::{PciDeviceInfo, PreferredInterruptMode},
PciBaseAddress, PciCommandRegister, PciConfigurationSpace, PciBaseAddress, PciCommandRegister, PciConfigurationSpace,
@ -12,13 +13,28 @@ use ygg_driver_pci::{
extern crate alloc; extern crate alloc;
pub mod rtl8139; pub mod rtl8139;
pub mod rtl8168;
pub fn probe_8169(_info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> { pub fn probe_8168(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
todo!() let base = info
.config_space
.bar(2)
.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);
// }
// 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<Arc<dyn Device>, Error> { pub fn probe_8139(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
info.init_interrupts(PreferredInterruptMode::Msi)?; info.init_interrupts(PreferredInterruptMode::Msi(false))?;
// Enable MMIO + interrupts + bus mastering // Enable MMIO + interrupts + bus mastering
let mut command = info.config_space.command(); let mut command = info.config_space.command();

View File

@ -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<u32>; 2]),
(0x0008 => MARn: [ReadWrite<u32>; 2]),
(0x0010 => DTCCR: ReadWrite<u64>),
(0x0018 => _0),
(0x0020 => TNPDS: [ReadWrite<u32>; 2]),
(0x0028 => THPDS: [ReadWrite<u32>; 2]),
(0x0030 => _1),
(0x0037 => CR: ReadWrite<u8, CR::Register>),
(0x0038 => TPPOLL: WriteOnly<u8, TPPOLL::Register>),
(0x0039 => _2),
(0x003C => IMR: ReadWrite<u16, IMR_ISR::Register>),
(0x003E => ISR: ReadWrite<u16, IMR_ISR::Register>),
(0x0040 => TCR: ReadWrite<u32, TCR::Register>),
(0x0044 => RCR: ReadWrite<u32, RCR::Register>),
(0x0048 => TCTR: ReadWrite<u32>),
(0x004C => MPKT: ReadWrite<u32>),
(0x0050 => R9346CR: ReadWrite<u8>),
(0x0051 => CONFIG0: ReadWrite<u8>),
(0x0052 => CONFIG1: ReadWrite<u8>),
(0x0053 => CONFIG2: ReadWrite<u8>),
(0x0054 => CONFIG3: ReadWrite<u8>),
(0x0055 => CONFIG4: ReadWrite<u8>),
(0x0056 => CONFIG5: ReadWrite<u8>),
(0x0057 => _4),
(0x0058 => TIMERINT: ReadWrite<u32>),
(0x005C => _5),
(0x0060 => PHYAR: ReadWrite<u32, PHYAR::Register>),
(0x0064 => _6),
(0x006C => PHYSTATUS: ReadOnly<u8, PHYSTATUS::Register>),
(0x006D => _7),
(0x0084 => WAKEUPn: [ReadWrite<u32>; 16]),
(0x00C4 => CRCn: [ReadWrite<u16>; 5]),
(0x00CE => _8),
(0x00DA => RMS: ReadWrite<u16>),
(0x00DC => _9),
(0x00E0 => CPCR: ReadWrite<u16, CPCR::Register>),
(0x00E2 => _10),
(0x00E4 => RDSAR: [ReadWrite<u32>; 2]),
(0x00EC => MTPS: ReadWrite<u8>),
(0x00ED => _11),
(0x00F0 => MISC: ReadWrite<u32>),
(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<PageBox<[MaybeUninit<u8>]>>,
rd: usize,
}
struct TxRing {
entries: PageBox<[Descriptor]>,
buffers: Vec<Option<PageBox<[u8]>>>,
wr: usize,
rd: usize,
}
pub struct Rtl8168 {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
mac: MacAddress,
pci: PciDeviceInfo,
nic: OneTimeInit<u32>,
rx: OneTimeInit<IrqSafeSpinlock<RxRing>>,
tx: OneTimeInit<IrqSafeSpinlock<TxRing>>,
}
impl RxRing {
pub fn with_capacity(capacity: usize) -> Result<Self, Error> {
let buffers = (0..capacity)
.map(|_| PageBox::new_uninit_slice(4096))
.collect::<Result<Vec<_>, _>>()?;
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<F: Fn(PageBox<[u8]>)>(&mut self, handler: F) -> Result<usize, Error> {
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<Self, Error> {
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<usize, Error> {
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<u16, Error> {
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<Self, Error> {
let regs = unsafe { DeviceMemoryIo::<Regs>::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<Self>, _vector: Option<usize>) -> 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<Self>) -> 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(),
}
}
}

View File

@ -103,7 +103,7 @@ pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let regs = unsafe { xhci_lib::Registers::new(bar0.try_into_usize().unwrap(), Mapper::new()) }; let regs = unsafe { xhci_lib::Registers::new(bar0.try_into_usize().unwrap(), Mapper::new()) };
let xhci = Arc::new(Xhci::new(regs)?); 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())?; info.map_interrupt(InterruptAffinity::Any, xhci.clone())?;
Ok(xhci) Ok(xhci)

View File

@ -176,7 +176,7 @@ impl<T: Transport + 'static> VirtioNet<T> {
transmit_count: usize, transmit_count: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
let receive_vector = if let Some(pci) = self.pci_device_info.as_ref() { 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())?; let info = pci.map_interrupt(InterruptAffinity::Any, self.clone())?;
info.map(|info| info.vector as u16) info.map(|info| info.vector as u16)

View File

@ -70,13 +70,13 @@ pub fn register_pci_drivers() {
Some(0x01), Some(0x01),
ygg_driver_ahci::probe, ygg_driver_ahci::probe,
); );
// ygg_driver_pci::register_class_driver( ygg_driver_pci::register_class_driver(
// "USB xHCI", "USB xHCI",
// 0x0C, 0x0C,
// Some(0x03), Some(0x03),
// Some(0x30), Some(0x30),
// ygg_driver_usb_xhci::probe, ygg_driver_usb_xhci::probe,
// ); );
ygg_driver_pci::register_vendor_driver( ygg_driver_pci::register_vendor_driver(
"Virtio PCI GPU Device", "Virtio PCI GPU Device",
0x1AF4, 0x1AF4,
@ -96,10 +96,10 @@ pub fn register_pci_drivers() {
ygg_driver_net_rtl81xx::probe_8139, ygg_driver_net_rtl81xx::probe_8139,
); );
ygg_driver_pci::register_vendor_driver( ygg_driver_pci::register_vendor_driver(
"Realtek RTL8169/8110 Gigabit Ethernet", "Realtek RTL8168/8111 Gigabit Ethernet",
0x10EC, 0x10EC,
0x8169, 0x8168,
ygg_driver_net_rtl81xx::probe_8169, ygg_driver_net_rtl81xx::probe_8168,
); );
} }

View File

@ -64,7 +64,7 @@ struct Inner {
pub struct IoApic { pub struct IoApic {
inner: IrqSafeSpinlock<Inner>, inner: IrqSafeSpinlock<Inner>,
isa_redirections: [Option<IsaRedirection>; 16], isa_redirections: [Option<IsaRedirection>; 16],
table: IrqSafeRwLock<FixedInterruptTable<{ POPULATED_EXTERNAL_VECTORS as usize }>>, // table: IrqSafeSpinlock<FixedInterruptTable<{ POPULATED_EXTERNAL_VECTORS as usize }>>, table: IrqSafeRwLock<FixedInterruptTable<{ POPULATED_EXTERNAL_VECTORS as usize }>>,
} }
impl Regs { impl Regs {

View File

@ -259,7 +259,7 @@ impl MessageInterruptController for LocalApic {
); );
let value = 32 + APIC_MSI_OFFSET + i as u32; 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 { *msi = MsiInfo {
address, address,