WIP: implement igbe driver
This commit is contained in:
parent
f1becafaaf
commit
0a46e6f57c
64
Cargo.lock
generated
64
Cargo.lock
generated
@ -17,7 +17,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@ -193,7 +193,7 @@ checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -213,7 +213,7 @@ checksum = "99e1aca718ea7b89985790c94aad72d77533063fe00bc497bb79a7c2dae6a661"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -315,7 +315,7 @@ checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -386,7 +386,7 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -479,7 +479,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -515,7 +515,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -567,7 +567,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -787,7 +787,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1004,7 +1004,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1612,7 +1612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1898,7 +1898,7 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1992,9 +1992,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.96"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2009,7 +2009,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2062,7 +2062,7 @@ checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2082,7 +2082,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2130,7 +2130,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2352,7 +2352,7 @@ dependencies = [
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@ -2374,7 +2374,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@ -2689,6 +2689,21 @@ dependencies = [
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_net_igbe"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"device-api",
|
||||
"libk",
|
||||
"libk-mm",
|
||||
"libk-util",
|
||||
"log",
|
||||
"tock-registers",
|
||||
"ygg_driver_net_core",
|
||||
"ygg_driver_pci",
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_net_loopback"
|
||||
version = "0.1.0"
|
||||
@ -2912,6 +2927,7 @@ dependencies = [
|
||||
"ygg_driver_fat32",
|
||||
"ygg_driver_input",
|
||||
"ygg_driver_net_core",
|
||||
"ygg_driver_net_igbe",
|
||||
"ygg_driver_net_loopback",
|
||||
"ygg_driver_net_rtl81xx",
|
||||
"ygg_driver_nvme",
|
||||
@ -2959,7 +2975,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@ -2981,7 +2997,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3001,7 +3017,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@ -3024,5 +3040,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
@ -67,6 +67,7 @@ kernel-arch-x86_64.workspace = true
|
||||
kernel-arch-x86.workspace = true
|
||||
|
||||
ygg_driver_acpi.path = "driver/acpi"
|
||||
ygg_driver_net_igbe.path = "driver/net/igbe"
|
||||
|
||||
acpi.workspace = true
|
||||
|
||||
|
@ -622,12 +622,21 @@ fn setup_bus_device(device: &mut PciBusDevice) -> Result<(), Error> {
|
||||
dma_allocator: dma.clone(),
|
||||
};
|
||||
|
||||
let instance = driver.probe(&device.info, &dma)?;
|
||||
match driver.probe(&device.info, &dma) {
|
||||
Ok(instance) => {
|
||||
unsafe { instance.clone().init(cx) }?;
|
||||
|
||||
unsafe { instance.clone().init(cx) }?;
|
||||
|
||||
device.device.replace(instance);
|
||||
device.driver_name.replace(driver.driver_name());
|
||||
device.device.replace(instance);
|
||||
device.driver_name.replace(driver.driver_name());
|
||||
}
|
||||
Err(error) => {
|
||||
log::error!(
|
||||
"{} ({}): {error:?}",
|
||||
device.info.address,
|
||||
driver.driver_name()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -14,7 +14,7 @@ pub macro pci_driver_match {
|
||||
}
|
||||
|
||||
pub macro pci_driver(
|
||||
matches: [$($kind:ident $match:tt),+],
|
||||
matches: [$($kind:ident $match:tt),+ $(,)?],
|
||||
driver: $driver:tt
|
||||
) {
|
||||
#[link_section = ".init_array"]
|
||||
|
@ -339,7 +339,7 @@ pub trait PciConfigurationSpace {
|
||||
Some(PciBaseAddress::Memory32(w0 & !0xF))
|
||||
}
|
||||
// TODO can 64-bit BARs not be on a 64-bit boundary?
|
||||
2 => todo!(),
|
||||
2 => None,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
1 => todo!(),
|
||||
|
17
kernel/driver/net/igbe/Cargo.toml
Normal file
17
kernel/driver/net/igbe/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "ygg_driver_net_igbe"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
device-api.workspace = true
|
||||
yggdrasil-abi.workspace = true
|
||||
libk-mm.workspace = true
|
||||
libk-util.workspace = true
|
||||
libk.workspace = true
|
||||
|
||||
ygg_driver_pci.path = "../../bus/pci"
|
||||
ygg_driver_net_core.path = "../core"
|
||||
|
||||
log.workspace = true
|
||||
tock-registers.workspace = true
|
414
kernel/driver/net/igbe/src/lib.rs
Normal file
414
kernel/driver/net/igbe/src/lib.rs
Normal file
@ -0,0 +1,414 @@
|
||||
#![no_std]
|
||||
|
||||
use core::mem::{self, MaybeUninit};
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
dma::DmaAllocator,
|
||||
interrupt::{InterruptAffinity, InterruptHandler, IrqVector},
|
||||
};
|
||||
use libk::{
|
||||
dma::{BusAddress, DmaBuffer},
|
||||
error::Error,
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{
|
||||
sync::{IrqSafeSpinlock, Spinlock},
|
||||
OneTimeInit,
|
||||
};
|
||||
use regs::{Regs, ICR};
|
||||
use tock_registers::interfaces::Writeable;
|
||||
use ygg_driver_net_core::{
|
||||
interface::{NetworkDevice, NetworkInterfaceType},
|
||||
register_interface, Packet,
|
||||
};
|
||||
use ygg_driver_pci::{
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
PciBaseAddress, PciCommandRegister, PciConfigurationSpace,
|
||||
};
|
||||
use yggdrasil_abi::net::MacAddress;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod regs;
|
||||
|
||||
struct RxRing {
|
||||
descriptors: DmaBuffer<[RxDescriptor]>,
|
||||
buffers: Vec<DmaBuffer<[MaybeUninit<u8>]>>,
|
||||
buffer_size: usize,
|
||||
tail: u16,
|
||||
}
|
||||
|
||||
struct TxRing {
|
||||
descriptors: DmaBuffer<[TxDescriptor]>,
|
||||
buffers: Vec<Option<DmaBuffer<[u8]>>>,
|
||||
// Consumer end
|
||||
tail: u16,
|
||||
// Producer end
|
||||
head: u16,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct RxDescriptor {
|
||||
address: BusAddress,
|
||||
length: u16,
|
||||
checksum: u16,
|
||||
status: u8,
|
||||
errors: u8,
|
||||
special: u16,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct TxDescriptor {
|
||||
address: BusAddress,
|
||||
length: u16,
|
||||
cso: u8,
|
||||
cmd: u8,
|
||||
sta: u8,
|
||||
_0: u8,
|
||||
css: u8,
|
||||
special: u8,
|
||||
}
|
||||
|
||||
impl RxRing {
|
||||
pub fn with_capacity(
|
||||
dma: &dyn DmaAllocator,
|
||||
capacity: usize,
|
||||
buffer_size: usize,
|
||||
) -> Result<Self, Error> {
|
||||
let buffers = (0..capacity)
|
||||
.map(|_| DmaBuffer::new_uninit_slice(dma, buffer_size))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let descriptors = DmaBuffer::new_slice_with(
|
||||
dma,
|
||||
|i| RxDescriptor::new(buffers[i].bus_address(), buffer_size as u16),
|
||||
capacity,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
descriptors,
|
||||
buffers,
|
||||
tail: 0,
|
||||
buffer_size,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO move to background task/softirq to reduce amount of code run by the irq handler
|
||||
pub fn handle_rx<F: FnMut(DmaBuffer<[u8]>, usize)>(
|
||||
&mut self,
|
||||
dma: &dyn DmaAllocator,
|
||||
head: u16,
|
||||
mut handler: F,
|
||||
) -> u16 {
|
||||
let capacity = self.descriptors.len();
|
||||
while self.tail != head {
|
||||
let index = self.tail as usize;
|
||||
// Replace the buffer
|
||||
|
||||
let new_buffer = DmaBuffer::new_uninit_slice(dma, self.buffer_size).unwrap();
|
||||
let new_buffer_address = new_buffer.bus_address();
|
||||
let buffer = mem::replace(&mut self.buffers[index], new_buffer);
|
||||
let buffer = unsafe { DmaBuffer::assume_init_slice(buffer) };
|
||||
|
||||
let descriptor = &mut self.descriptors[index];
|
||||
|
||||
if descriptor.errors & !1 != 0 {
|
||||
log::warn!("igbe: drop erroneous packet {:#x}", descriptor.errors);
|
||||
} else {
|
||||
let len = descriptor.length as usize;
|
||||
handler(buffer, len);
|
||||
}
|
||||
|
||||
// Replace the descriptor
|
||||
*descriptor = RxDescriptor::new(new_buffer_address, self.buffer_size as u16);
|
||||
|
||||
self.tail = (self.tail + 1) & (capacity as u16 - 1);
|
||||
}
|
||||
|
||||
(self.tail + capacity as u16 - 1) & (capacity as u16 - 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl TxRing {
|
||||
pub fn with_capacity(dma: &dyn DmaAllocator, capacity: usize) -> Result<Self, Error> {
|
||||
let buffers = (0..capacity).map(|_| None).collect::<Vec<_>>();
|
||||
let descriptors = DmaBuffer::new_slice_with(dma, |_| TxDescriptor::empty(), capacity)?;
|
||||
Ok(Self {
|
||||
descriptors,
|
||||
buffers,
|
||||
head: 0,
|
||||
tail: 0,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn handle_tx(&mut self, head: u16) {
|
||||
self.tail = self.head;
|
||||
}
|
||||
|
||||
pub fn tx_now(&mut self, buffer: DmaBuffer<[u8]>) -> Result<u16, DmaBuffer<[u8]>> {
|
||||
// Queue full
|
||||
let capacity = self.descriptors.len();
|
||||
if (self.head + 1) & (capacity as u16 - 1) == self.tail {
|
||||
log::warn!("igbe: tx queue full");
|
||||
return Err(buffer);
|
||||
}
|
||||
let index = self.head as usize;
|
||||
|
||||
let descriptor = &mut self.descriptors[index];
|
||||
// Only generate interrupts for every 1/4th of the buffer
|
||||
let quarter = capacity / 4;
|
||||
descriptor.setup_tx(
|
||||
buffer.bus_address(),
|
||||
buffer.len() as u16 - 4,
|
||||
index % quarter == quarter - 1,
|
||||
);
|
||||
self.descriptors.cache_flush_element(index);
|
||||
|
||||
self.buffers[index] = Some(buffer);
|
||||
|
||||
self.head = (self.head + 1) & (capacity as u16 - 1);
|
||||
Ok(self.head)
|
||||
}
|
||||
}
|
||||
|
||||
impl RxDescriptor {
|
||||
pub fn new(address: BusAddress, length: u16) -> Self {
|
||||
Self {
|
||||
address,
|
||||
length,
|
||||
checksum: 0,
|
||||
status: 0,
|
||||
errors: 0,
|
||||
special: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TxDescriptor {
|
||||
// Descriptor done
|
||||
const STA_DD: u8 = 1 << 0;
|
||||
// End of packet
|
||||
const CMD_EOP: u8 = 1 << 0;
|
||||
// Insert MAC FCS
|
||||
const CMD_IFCS: u8 = 1 << 1;
|
||||
// Insert checksum
|
||||
const CMD_IC: u8 = 1 << 2;
|
||||
// Report status
|
||||
const CMD_RS: u8 = 1 << 3;
|
||||
|
||||
pub const fn empty() -> Self {
|
||||
Self {
|
||||
address: BusAddress::ZERO,
|
||||
length: 0,
|
||||
cso: 0,
|
||||
cmd: 0,
|
||||
sta: Self::STA_DD,
|
||||
_0: 0,
|
||||
css: 0,
|
||||
special: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_tx(&mut self, address: BusAddress, length: u16, ioc: bool) {
|
||||
let mut cmd = Self::CMD_EOP | Self::CMD_IFCS;
|
||||
if ioc {
|
||||
cmd |= Self::CMD_RS;
|
||||
}
|
||||
self.address = address;
|
||||
self.length = length;
|
||||
self.css = 0;
|
||||
self.cso = 0;
|
||||
self.sta = 0;
|
||||
self.cmd = cmd;
|
||||
self.special = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct Igbe {
|
||||
regs: IrqSafeSpinlock<Regs>,
|
||||
base: PciBaseAddress,
|
||||
dma: Arc<dyn DmaAllocator>,
|
||||
pci: PciDeviceInfo,
|
||||
|
||||
mac: OneTimeInit<MacAddress>,
|
||||
rx_ring: OneTimeInit<Spinlock<RxRing>>,
|
||||
tx_ring: OneTimeInit<IrqSafeSpinlock<TxRing>>,
|
||||
nic: OneTimeInit<u32>,
|
||||
}
|
||||
|
||||
impl Igbe {
|
||||
pub fn new(
|
||||
dma: Arc<dyn DmaAllocator>,
|
||||
base: PciBaseAddress,
|
||||
regs: Regs,
|
||||
pci: PciDeviceInfo,
|
||||
) -> Self {
|
||||
Self {
|
||||
dma,
|
||||
base,
|
||||
pci,
|
||||
mac: OneTimeInit::new(),
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
|
||||
rx_ring: OneTimeInit::new(),
|
||||
tx_ring: OneTimeInit::new(),
|
||||
nic: OneTimeInit::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for Igbe {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
let msi_info = self
|
||||
.pci
|
||||
.map_interrupt(InterruptAffinity::Any, self.clone())?;
|
||||
|
||||
let rx_ring = RxRing::with_capacity(&*self.dma, 128, 2048 + 16)?;
|
||||
let tx_ring = TxRing::with_capacity(&*self.dma, 128)?;
|
||||
|
||||
let mut regs = self.regs.lock();
|
||||
|
||||
regs.disable_interrupts();
|
||||
let mac = regs.read_mac()?;
|
||||
self.mac.init(mac);
|
||||
regs.reset(1000000)?;
|
||||
// Intel 8257x manuals say an additional interrupt disable is needed after a global reset
|
||||
regs.disable_interrupts();
|
||||
regs.set_link_up()?;
|
||||
|
||||
// Initialize Rx
|
||||
regs.initialize_receiver(&rx_ring);
|
||||
regs.initialize_transmitter(&tx_ring);
|
||||
// If MSI(-x) was initialized, notify the NIC about it
|
||||
if let Some(msi_info) = msi_info {
|
||||
regs.initialize_ivar(msi_info.vector);
|
||||
}
|
||||
|
||||
self.rx_ring.init(Spinlock::new(rx_ring));
|
||||
self.tx_ring.init(IrqSafeSpinlock::new(tx_ring));
|
||||
let nic = register_interface(NetworkInterfaceType::Ethernet, self.clone());
|
||||
self.nic.init(nic.id());
|
||||
|
||||
regs.enable_interrupts();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
"Intel Gigabit Ethernet"
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptHandler for Igbe {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let mut regs = self.regs.lock();
|
||||
let cause = regs.interrupt_cause();
|
||||
if cause.get() == 0 {
|
||||
return false;
|
||||
}
|
||||
regs.clear_interrupts(cause.get());
|
||||
let mut any = false;
|
||||
|
||||
if cause.matches_all(ICR::LSC::SET) {
|
||||
let status = regs.read_link();
|
||||
log::info!("igbe: link is {status}");
|
||||
any = true;
|
||||
}
|
||||
|
||||
if cause.matches_all(ICR::RXT0::SET) {
|
||||
let mut rx = self.rx_ring.get().lock();
|
||||
let nic = *self.nic.get();
|
||||
let head = regs.rx_queue_head();
|
||||
let tail = rx.handle_rx(&*self.dma, head, |packet, _| {
|
||||
let packet = Packet::new(packet, 0, nic);
|
||||
ygg_driver_net_core::receive_packet(packet).ok();
|
||||
});
|
||||
regs.set_rx_queue_tail(tail);
|
||||
any = true;
|
||||
}
|
||||
|
||||
if cause.matches_any(&[ICR::TXQE::SET, ICR::TXDW::SET]) {
|
||||
let mut tx = self.tx_ring.get().lock();
|
||||
let head = regs.tx_queue_head();
|
||||
tx.handle_tx(head);
|
||||
any = true;
|
||||
}
|
||||
|
||||
if !any {
|
||||
log::info!("igbe: unhandled irq {:#x}", cause.get());
|
||||
}
|
||||
|
||||
any
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkDevice for Igbe {
|
||||
fn read_hardware_address(&self) -> MacAddress {
|
||||
*self.mac.get()
|
||||
}
|
||||
|
||||
fn packet_prefix_size(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn allocate_transmit_buffer(&self, len: usize) -> Result<DmaBuffer<[MaybeUninit<u8>]>, Error> {
|
||||
DmaBuffer::new_uninit_slice(&*self.dma, len + 4)
|
||||
}
|
||||
|
||||
fn transmit_buffer(&self, buffer: DmaBuffer<[u8]>) -> Result<(), Error> {
|
||||
let mut tx = self.tx_ring.get().lock();
|
||||
|
||||
let Ok(head) = tx.tx_now(buffer) else {
|
||||
return Err(Error::WouldBlock);
|
||||
};
|
||||
|
||||
let mut regs = self.regs.lock();
|
||||
regs.set_tx_queue_tail(head);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pci_driver! {
|
||||
matches: [
|
||||
device (0x8086:0x10C9), // 82576 GbE
|
||||
device (0x8086:0x1502), // 82579LM GbE (Lewisville)
|
||||
],
|
||||
driver: {
|
||||
fn probe(
|
||||
&self,
|
||||
info: &PciDeviceInfo,
|
||||
dma: &Arc<dyn DmaAllocator>,
|
||||
) -> Result<Arc<dyn Device>, Error> {
|
||||
let base = info
|
||||
.config_space
|
||||
.bar(0).ok_or(Error::InvalidArgument)?;
|
||||
|
||||
let mut command = info.config_space.command();
|
||||
command |= (PciCommandRegister::BUS_MASTER | PciCommandRegister::DISABLE_INTERRUPTS).bits();
|
||||
match base {
|
||||
PciBaseAddress::Memory32(_) | PciBaseAddress::Memory64(_) => {
|
||||
command |= PciCommandRegister::ENABLE_MEMORY.bits();
|
||||
command &= !PciCommandRegister::ENABLE_IO.bits();
|
||||
}
|
||||
PciBaseAddress::Io(_) => {
|
||||
command |= PciCommandRegister::ENABLE_IO.bits();
|
||||
command &= !PciCommandRegister::ENABLE_MEMORY.bits();
|
||||
}
|
||||
}
|
||||
info.config_space.set_command(command);
|
||||
|
||||
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
|
||||
|
||||
let regs = unsafe { Regs::map(base) }?;
|
||||
let device = Igbe::new(dma.clone(), base, regs, info.clone());
|
||||
Ok(Arc::new(device))
|
||||
}
|
||||
|
||||
fn driver_name(&self) -> &str {
|
||||
"igbe"
|
||||
}
|
||||
}
|
||||
}
|
516
kernel/driver/net/igbe/src/regs.rs
Normal file
516
kernel/driver/net/igbe/src/regs.rs
Normal file
@ -0,0 +1,516 @@
|
||||
#![allow(non_snake_case)]
|
||||
use core::{cell::UnsafeCell, marker::PhantomData, time};
|
||||
|
||||
use libk::error::Error;
|
||||
use libk_mm::{address::PhysicalAddress, device::RawDeviceMemoryMapping};
|
||||
use tock_registers::{fields::FieldValue, register_bitfields, LocalRegisterCopy, RegisterLongName};
|
||||
use ygg_driver_net_core::ethernet::{Duplex, EthernetLinkState, EthernetSpeed};
|
||||
use ygg_driver_pci::PciBaseAddress;
|
||||
use yggdrasil_abi::net::MacAddress;
|
||||
use TXDCTL::LWTHRESH;
|
||||
|
||||
use crate::{RxRing, TxRing};
|
||||
|
||||
enum Inner {
|
||||
Memory(RawDeviceMemoryMapping),
|
||||
Io(u16),
|
||||
}
|
||||
|
||||
enum Eeprom {
|
||||
Present,
|
||||
MappedMemory(RawDeviceMemoryMapping),
|
||||
MappedIo(u16),
|
||||
}
|
||||
|
||||
pub struct Regs {
|
||||
inner: Inner,
|
||||
eeprom: Eeprom,
|
||||
}
|
||||
|
||||
// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
// #[repr(u16)]
|
||||
// pub enum Register {
|
||||
// CTRL = 0x0000,
|
||||
// STATUS = 0x0008,
|
||||
// EEPROM = 0x0014,
|
||||
// IMS = 0x00D0,
|
||||
//
|
||||
// RCTL = 0x0100,
|
||||
// }
|
||||
|
||||
pub trait Reg {
|
||||
const OFFSET: u16;
|
||||
}
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
pub CTRL [
|
||||
SLU OFFSET(6) NUMBITS(1) [],
|
||||
RST OFFSET(26) NUMBITS(1) [],
|
||||
RFCE OFFSET(27) NUMBITS(1) [],
|
||||
TFCE OFFSET(28) NUMBITS(1) [],
|
||||
],
|
||||
pub STATUS [
|
||||
FD OFFSET(0) NUMBITS(1) [],
|
||||
LU OFFSET(1) NUMBITS(1) [],
|
||||
SPEED OFFSET(6) NUMBITS(2) [],
|
||||
],
|
||||
pub MDIC [
|
||||
DATA OFFSET(0) NUMBITS(16) [],
|
||||
REGADD OFFSET(16) NUMBITS(5) [],
|
||||
PHYADD OFFSET(21) NUMBITS(5) [],
|
||||
OP OFFSET(26) NUMBITS(2) [
|
||||
Write = 0b01,
|
||||
Read = 0b10
|
||||
],
|
||||
R OFFSET(28) NUMBITS(1) [],
|
||||
I OFFSET(29) NUMBITS(1) [],
|
||||
E OFFSET(30) NUMBITS(1) [],
|
||||
],
|
||||
pub ICR [
|
||||
TXDW OFFSET(0) NUMBITS(1) [],
|
||||
TXQE OFFSET(1) NUMBITS(1) [],
|
||||
LSC OFFSET(2) NUMBITS(1) [],
|
||||
RXT0 OFFSET(7) NUMBITS(1) [],
|
||||
],
|
||||
pub IMS [
|
||||
TXDW OFFSET(0) NUMBITS(1) [],
|
||||
TXQE OFFSET(1) NUMBITS(1) [],
|
||||
LSC OFFSET(2) NUMBITS(1) [],
|
||||
RXT0 OFFSET(7) NUMBITS(1) [],
|
||||
],
|
||||
pub RCTL [
|
||||
EN OFFSET(1) NUMBITS(1) [],
|
||||
UPE OFFSET(3) NUMBITS(1) [],
|
||||
MPE OFFSET(4) NUMBITS(1) [],
|
||||
BAM OFFSET(15) NUMBITS(1) [],
|
||||
BSIZE OFFSET(16) NUMBITS(2) [
|
||||
SIZE_2048 = 0b00,
|
||||
SIZE_1024_16384 = 0b01,
|
||||
SIZE_512_8192 = 0b10,
|
||||
SIZE_256_4096 = 0b11
|
||||
],
|
||||
BSEX OFFSET(25) NUMBITS(1) [],
|
||||
],
|
||||
pub RDLEN0 [
|
||||
LEN0 OFFSET(7) NUMBITS(13) [],
|
||||
],
|
||||
pub CPUVEC [
|
||||
CPUVEC OFFSET(0) NUMBITS(32) [],
|
||||
],
|
||||
pub TCTL [
|
||||
EN OFFSET(1) NUMBITS(1) [],
|
||||
PSP OFFSET(3) NUMBITS(1) [],
|
||||
CT OFFSET(4) NUMBITS(8) [],
|
||||
COLD OFFSET(12) NUMBITS(10) [],
|
||||
MULR OFFSET(28) NUMBITS(1) [],
|
||||
],
|
||||
pub TDLEN [
|
||||
LEN OFFSET(7) NUMBITS(13) [],
|
||||
],
|
||||
pub TIDV [
|
||||
IDV OFFSET(0) NUMBITS(16) [],
|
||||
],
|
||||
pub TXDCTL [
|
||||
PTHRESH OFFSET(0) NUMBITS(6) [],
|
||||
HTHRESH OFFSET(8) NUMBITS(8) [],
|
||||
WTHRESH OFFSET(16) NUMBITS(6) [],
|
||||
GRAN OFFSET(24) NUMBITS(1) [],
|
||||
LWTHRESH OFFSET(25) NUMBITS(7) [],
|
||||
],
|
||||
pub TADV [
|
||||
IDV OFFSET(0) NUMBITS(16) [],
|
||||
],
|
||||
}
|
||||
pub mod IMC {
|
||||
pub struct Register;
|
||||
}
|
||||
pub mod RDBAL0 {
|
||||
pub struct Register;
|
||||
}
|
||||
pub mod RDBAH0 {
|
||||
pub struct Register;
|
||||
}
|
||||
pub mod RDH0 {
|
||||
pub struct Register;
|
||||
}
|
||||
pub mod RDT0 {
|
||||
pub struct Register;
|
||||
}
|
||||
pub mod TIPG {
|
||||
pub struct Register;
|
||||
}
|
||||
pub mod TDBAL {
|
||||
pub struct Register;
|
||||
}
|
||||
pub mod TDBAH {
|
||||
pub struct Register;
|
||||
}
|
||||
pub mod TDH {
|
||||
pub struct Register;
|
||||
}
|
||||
pub mod TDT {
|
||||
pub struct Register;
|
||||
}
|
||||
pub mod IVAR {
|
||||
pub struct Register;
|
||||
}
|
||||
|
||||
impl Reg for CTRL::Register {
|
||||
const OFFSET: u16 = 0x0000;
|
||||
}
|
||||
impl Reg for STATUS::Register {
|
||||
const OFFSET: u16 = 0x0008;
|
||||
}
|
||||
impl Reg for MDIC::Register {
|
||||
const OFFSET: u16 = 0x0020;
|
||||
}
|
||||
impl Reg for ICR::Register {
|
||||
const OFFSET: u16 = 0x00C0;
|
||||
}
|
||||
impl Reg for IMS::Register {
|
||||
const OFFSET: u16 = 0x00D0;
|
||||
}
|
||||
impl Reg for IMC::Register {
|
||||
const OFFSET: u16 = 0x00D8;
|
||||
}
|
||||
impl Reg for RCTL::Register {
|
||||
const OFFSET: u16 = 0x0100;
|
||||
}
|
||||
impl Reg for RDBAL0::Register {
|
||||
const OFFSET: u16 = 0x2800;
|
||||
}
|
||||
impl Reg for RDBAH0::Register {
|
||||
const OFFSET: u16 = 0x2804;
|
||||
}
|
||||
impl Reg for RDLEN0::Register {
|
||||
const OFFSET: u16 = 0x2808;
|
||||
}
|
||||
impl Reg for RDH0::Register {
|
||||
const OFFSET: u16 = 0x2810;
|
||||
}
|
||||
impl Reg for RDT0::Register {
|
||||
const OFFSET: u16 = 0x2818;
|
||||
}
|
||||
impl Reg for CPUVEC::Register {
|
||||
const OFFSET: u16 = 0x2C10;
|
||||
}
|
||||
impl Reg for TCTL::Register {
|
||||
const OFFSET: u16 = 0x0400;
|
||||
}
|
||||
impl Reg for TIPG::Register {
|
||||
const OFFSET: u16 = 0x0410;
|
||||
}
|
||||
impl Reg for TDBAL::Register {
|
||||
const OFFSET: u16 = 0x3800;
|
||||
}
|
||||
impl Reg for TDBAH::Register {
|
||||
const OFFSET: u16 = 0x3804;
|
||||
}
|
||||
impl Reg for TDLEN::Register {
|
||||
const OFFSET: u16 = 0x3808;
|
||||
}
|
||||
impl Reg for TDH::Register {
|
||||
const OFFSET: u16 = 0x3810;
|
||||
}
|
||||
impl Reg for TDT::Register {
|
||||
const OFFSET: u16 = 0x3818;
|
||||
}
|
||||
impl Reg for TIDV::Register {
|
||||
const OFFSET: u16 = 0x3820;
|
||||
}
|
||||
impl Reg for TXDCTL::Register {
|
||||
const OFFSET: u16 = 0x3828;
|
||||
}
|
||||
impl Reg for TADV::Register {
|
||||
const OFFSET: u16 = 0x382C;
|
||||
}
|
||||
impl Reg for IVAR::Register {
|
||||
const OFFSET: u16 = 0x1700;
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
unsafe fn map(bar: PciBaseAddress) -> Result<Self, Error> {
|
||||
let memory_base = match bar {
|
||||
PciBaseAddress::Memory64(base) => PhysicalAddress::from_u64(base),
|
||||
PciBaseAddress::Memory32(base) => PhysicalAddress::from_u32(base),
|
||||
PciBaseAddress::Io(io_base) => {
|
||||
return Ok(Self::Io(io_base));
|
||||
}
|
||||
};
|
||||
|
||||
RawDeviceMemoryMapping::map(memory_base.into_u64(), 0x4000, Default::default())
|
||||
.map(Self::Memory)
|
||||
}
|
||||
|
||||
fn get<R: Reg>(&mut self) -> u32 {
|
||||
// let reg = reg as u16;
|
||||
match self {
|
||||
Self::Memory(mapping) => {
|
||||
let ptr: *const u32 =
|
||||
core::ptr::with_exposed_provenance(mapping.address + R::OFFSET as usize);
|
||||
unsafe { ptr.read_volatile() }
|
||||
}
|
||||
Self::Io(io) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn extract<R: Reg + RegisterLongName>(&mut self) -> LocalRegisterCopy<u32, R> {
|
||||
LocalRegisterCopy::new(self.get::<R>())
|
||||
}
|
||||
|
||||
fn write<R: Reg + RegisterLongName>(&mut self, value: FieldValue<u32, R>) {
|
||||
self.set::<R>(value.value);
|
||||
}
|
||||
|
||||
fn set<R: Reg>(&mut self, value: u32) {
|
||||
// log::info!("write({:#x}, {:#x})", R::OFFSET, value);
|
||||
match self {
|
||||
Self::Memory(mapping) => {
|
||||
let ptr: *mut u32 =
|
||||
core::ptr::with_exposed_provenance_mut(mapping.address + R::OFFSET as usize);
|
||||
unsafe { ptr.write_volatile(value) };
|
||||
}
|
||||
Self::Io(io) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn modify<R: Reg + RegisterLongName>(&mut self, modify: FieldValue<u32, R>) {
|
||||
let mut value = self.get::<R>();
|
||||
value &= !modify.mask();
|
||||
value |= modify.value;
|
||||
self.set::<R>(value);
|
||||
}
|
||||
|
||||
fn matches_all<R: Reg + RegisterLongName>(&mut self, pattern: FieldValue<u32, R>) -> bool {
|
||||
pattern.matches_all(self.get::<R>())
|
||||
}
|
||||
|
||||
// fn detect_eeprom(&mut self, mut timeout_cycles: u64) -> bool {
|
||||
// self.write(Register::EEPROM, 0x01);
|
||||
// while timeout_cycles > 0 && self.read(Register::EEPROM) & 0x10 == 0 {
|
||||
// core::hint::spin_loop();
|
||||
// timeout_cycles -= 1;
|
||||
// }
|
||||
// timeout_cycles > 0
|
||||
// }
|
||||
}
|
||||
|
||||
impl Eeprom {
|
||||
fn read(&mut self, inner: &mut Inner, addr: u8) -> u16 {
|
||||
match self {
|
||||
Self::Present => todo!(),
|
||||
Self::MappedMemory(mapping) => {
|
||||
let shift = (addr as usize & 1) << 4;
|
||||
let reg = (addr as usize & !1) << 1;
|
||||
let ptr: *const u32 = core::ptr::with_exposed_provenance(mapping.address + reg);
|
||||
let word = unsafe { ptr.read_volatile() };
|
||||
(word >> shift) as u16
|
||||
}
|
||||
&mut Self::MappedIo(io_base) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
pub unsafe fn map(bar: PciBaseAddress) -> Result<Self, Error> {
|
||||
let mut inner = Inner::map(bar)?;
|
||||
// let eeprom = if inner.detect_eeprom(10000) {
|
||||
// Eeprom::Present
|
||||
// } else {
|
||||
// Map EEPROM registers
|
||||
let eeprom = match &inner {
|
||||
Inner::Memory(mapping) => {
|
||||
let base = mapping.physical_base + ((mapping.address & 0xFFF) + 0x5400) as u64;
|
||||
let mapping = RawDeviceMemoryMapping::map(base, 0x10, Default::default())?;
|
||||
Eeprom::MappedMemory(mapping)
|
||||
}
|
||||
&Inner::Io(io) => todo!(),
|
||||
};
|
||||
//};
|
||||
Ok(Self { inner, eeprom })
|
||||
}
|
||||
|
||||
fn read_eeprom(&mut self, addr: u8) -> u16 {
|
||||
self.eeprom.read(&mut self.inner, addr)
|
||||
}
|
||||
|
||||
pub fn read_mac(&mut self) -> Result<MacAddress, Error> {
|
||||
let w0 = self.read_eeprom(0);
|
||||
let w1 = self.read_eeprom(1);
|
||||
let w2 = self.read_eeprom(2);
|
||||
if w0 == 0 && w1 == 0 && w2 == 0 {
|
||||
log::error!("Could not read EEPROM MAC address");
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
let w0 = w0.to_le_bytes();
|
||||
let w1 = w1.to_le_bytes();
|
||||
let w2 = w2.to_le_bytes();
|
||||
|
||||
let octets = [w0[0], w0[1], w1[0], w1[1], w2[0], w2[1]];
|
||||
Ok(MacAddress::from(octets))
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, mut timeout_cycles: u64) -> Result<(), Error> {
|
||||
self.inner.write(CTRL::RST::SET);
|
||||
|
||||
for _ in 0..10000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
|
||||
while timeout_cycles > 0 && self.inner.matches_all(CTRL::RST::SET) {
|
||||
timeout_cycles -= 1;
|
||||
}
|
||||
|
||||
if timeout_cycles > 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::TimedOut)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_link_up(&mut self) -> Result<(), Error> {
|
||||
self.inner
|
||||
.modify(CTRL::SLU::SET + CTRL::RFCE::SET + CTRL::TFCE::SET);
|
||||
|
||||
// Reset the PHY
|
||||
self.mdio_write(0x00, 1 << 15, 1000)?;
|
||||
for _ in 0..1000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
// Start auto-negotiation
|
||||
self.mdio_write(0x00, (1 << 12) | (1 << 9), 1000)?;
|
||||
for _ in 0..1000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_link(&mut self) -> EthernetLinkState {
|
||||
let status = self.inner.extract::<STATUS::Register>();
|
||||
|
||||
if status.matches_all(STATUS::LU::SET) {
|
||||
let duplex = if status.matches_all(STATUS::FD::SET) {
|
||||
Duplex::Full
|
||||
} else {
|
||||
Duplex::Half
|
||||
};
|
||||
|
||||
let speed = match status.read(STATUS::SPEED) {
|
||||
0b00 => EthernetSpeed::Speed10,
|
||||
0b01 => EthernetSpeed::Speed100,
|
||||
0b10 | 0b11 => EthernetSpeed::Speed1000,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
EthernetLinkState::Up(speed, duplex)
|
||||
} else {
|
||||
EthernetLinkState::Down
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disable_interrupts(&mut self) {
|
||||
self.inner.set::<IMC::Register>(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
pub fn clear_interrupts(&mut self, cause: u32) {
|
||||
let _ = self.inner.get::<CPUVEC::Register>();
|
||||
self.inner.set::<ICR::Register>(cause);
|
||||
}
|
||||
|
||||
pub fn enable_interrupts(&mut self) {
|
||||
self.inner.set::<IMS::Register>(0xFFFFFFFF);
|
||||
// self.inner
|
||||
// .modify(IMS::LSC::SET + IMS::RXT0::SET + IMS::TXDW::SET + IMS::TXQE::SET);
|
||||
}
|
||||
|
||||
pub fn interrupt_cause(&mut self) -> LocalRegisterCopy<u32, ICR::Register> {
|
||||
self.inner.extract()
|
||||
}
|
||||
|
||||
pub fn mdio_write(&mut self, reg: u8, value: u16, mut timeout: u64) -> Result<(), Error> {
|
||||
self.inner.write(
|
||||
MDIC::DATA.val(value as u32)
|
||||
+ MDIC::PHYADD.val(1)
|
||||
+ MDIC::REGADD.val(reg as u32)
|
||||
+ MDIC::OP::Write,
|
||||
);
|
||||
while timeout > 0 && self.inner.matches_all(MDIC::R::CLEAR + MDIC::E::CLEAR) {
|
||||
timeout -= 1;
|
||||
}
|
||||
if timeout > 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::TimedOut)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mdio_read(&mut self, reg: u8, mut timeout: u64) -> Result<u16, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn initialize_receiver(&mut self, rx_ring: &RxRing) {
|
||||
let rx_queue_base = rx_ring.descriptors.bus_address().into_u64();
|
||||
self.inner.set::<RDBAL0::Register>(rx_queue_base as u32);
|
||||
self.inner
|
||||
.set::<RDBAH0::Register>((rx_queue_base >> 32) as u32);
|
||||
|
||||
self.inner
|
||||
.write(RDLEN0::LEN0.val((rx_ring.descriptors.len() / 8) as u32));
|
||||
self.inner.set::<RDH0::Register>(0);
|
||||
self.inner
|
||||
.set::<RDT0::Register>((rx_ring.descriptors.len() - 1) as u32);
|
||||
|
||||
self.inner.write(
|
||||
RCTL::EN::SET
|
||||
+ RCTL::BSIZE::SIZE_2048
|
||||
+ RCTL::BAM::SET
|
||||
+ RCTL::UPE::SET
|
||||
+ RCTL::MPE::SET,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn initialize_transmitter(&mut self, tx_ring: &TxRing) {
|
||||
let tx_queue_base = tx_ring.descriptors.bus_address().into_u64();
|
||||
self.inner.set::<TDBAL::Register>(tx_queue_base as u32);
|
||||
self.inner
|
||||
.set::<TDBAH::Register>((tx_queue_base >> 32) as u32);
|
||||
|
||||
self.inner
|
||||
.write(TDLEN::LEN.val((tx_ring.descriptors.len() / 8) as u32));
|
||||
self.inner.set::<TDT::Register>(0);
|
||||
self.inner.set::<TDH::Register>(0);
|
||||
|
||||
self.inner.set::<TIPG::Register>(0x0060200A);
|
||||
self.inner.write(TIDV::IDV.val(100));
|
||||
self.inner.write(TADV::IDV.val(100));
|
||||
self.inner
|
||||
.write(TCTL::EN::SET + TCTL::CT.val(15) + TCTL::COLD.val(63) + TCTL::PSP::SET);
|
||||
}
|
||||
|
||||
pub fn initialize_ivar(&mut self, vector: usize) {
|
||||
// Setup vector info for Tx/Rx queues 0
|
||||
let mut val = 0;
|
||||
for i in 0..4 {
|
||||
val |= (0x80 | (vector as u32 & 0xFF)) << (8 * i);
|
||||
}
|
||||
self.inner.set::<IVAR::Register>(val);
|
||||
}
|
||||
|
||||
pub fn rx_queue_head(&mut self) -> u16 {
|
||||
self.inner.get::<RDH0::Register>() as u16
|
||||
}
|
||||
|
||||
pub fn set_rx_queue_tail(&mut self, tail: u16) {
|
||||
self.inner.set::<RDT0::Register>(tail as u32);
|
||||
}
|
||||
|
||||
pub fn tx_queue_head(&mut self) -> u16 {
|
||||
self.inner.get::<TDH::Register>() as u16
|
||||
}
|
||||
|
||||
pub fn set_tx_queue_tail(&mut self, tail: u16) {
|
||||
self.inner.set::<TDT::Register>(tail as u32);
|
||||
}
|
||||
}
|
@ -69,6 +69,12 @@ extern crate ygg_driver_usb_xhci;
|
||||
extern crate ygg_driver_virtio_gpu;
|
||||
extern crate ygg_driver_virtio_net;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
extern crate ygg_driver_net_igbe;
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
pub mod arch;
|
||||
|
||||
|
@ -6,6 +6,7 @@ use crate::IntoArgs;
|
||||
pub enum QemuNic {
|
||||
VirtioPci { mac: Option<String> },
|
||||
Rtl8139 { mac: Option<String> },
|
||||
IntelGigabit { mac: Option<String> },
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
@ -56,6 +57,15 @@ impl IntoArgs for QemuNic {
|
||||
}
|
||||
command.arg(val);
|
||||
}
|
||||
Self::IntelGigabit { mac } => {
|
||||
command.arg("-device");
|
||||
let mut val = "igb,netdev=net0".to_owned();
|
||||
if let Some(mac) = mac {
|
||||
val.push_str(",mac=");
|
||||
val.push_str(mac);
|
||||
}
|
||||
command.arg(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ enum QemuNetworkInterface {
|
||||
#[default]
|
||||
VirtioNet,
|
||||
Rtl8139,
|
||||
IntelGigabit,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||
@ -325,6 +326,7 @@ fn add_devices_from_config(
|
||||
let nic = match config.network.interface {
|
||||
QemuNetworkInterface::VirtioNet => QemuNic::VirtioPci { mac },
|
||||
QemuNetworkInterface::Rtl8139 => QemuNic::Rtl8139 { mac },
|
||||
QemuNetworkInterface::IntelGigabit => QemuNic::IntelGigabit { mac },
|
||||
};
|
||||
devices.push(QemuDevice::NetworkTap {
|
||||
nic,
|
||||
|
Loading…
x
Reference in New Issue
Block a user