rtl81xx: fix rtl8168h (rtl8168gu still broken)
This commit is contained in:
parent
2867597c8e
commit
90edc4c8ed
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2722,6 +2722,7 @@ name = "ygg_driver_net_rtl81xx"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"device-api",
|
||||
"futures-util",
|
||||
"libk",
|
||||
"libk-mm",
|
||||
"libk-util",
|
||||
|
@ -251,7 +251,7 @@ impl NvmeController {
|
||||
)?;
|
||||
ioq.wait_for_completion(cmd_id, ()).await?;
|
||||
|
||||
ArchitectureImpl::memory_barrier();
|
||||
buffer.cache_flush_all(false);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -263,8 +263,7 @@ impl NvmeController {
|
||||
lba_count: usize,
|
||||
buffer: DmaSlice<'_, u8>,
|
||||
) -> Result<(), NvmeError> {
|
||||
buffer.cache_flush_all();
|
||||
ArchitectureImpl::store_barrier();
|
||||
buffer.cache_flush_all(true);
|
||||
|
||||
let prp_list = PrpList::from_buffer(&*self.dma, buffer.bus_address(), buffer.len())?;
|
||||
let cpu_index = cpu_index();
|
||||
|
@ -255,12 +255,12 @@ impl<T> Queue<T> {
|
||||
self.tail = new_tail;
|
||||
|
||||
if !self.tail_doorbell.is_null() {
|
||||
self.data.cache_flush_element(self.tail);
|
||||
ArchitectureImpl::store_barrier();
|
||||
self.data.cache_flush_element(self.tail, true);
|
||||
unsafe {
|
||||
self.tail_doorbell
|
||||
.write_volatile(self.tail.try_into().unwrap());
|
||||
}
|
||||
ArchitectureImpl::memory_barrier();
|
||||
}
|
||||
|
||||
wrapped
|
||||
|
@ -14,6 +14,7 @@ use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
capability::{MsiCapability, MsiXCapability, MsiXVectorTable},
|
||||
driver::PciDriver,
|
||||
PciAddress, PciCommandRegister, PciConfigSpace, PciConfigurationSpace, PciSegmentInfo,
|
||||
};
|
||||
|
||||
@ -90,11 +91,20 @@ pub struct PciMsiRoute {
|
||||
pub controller: Arc<dyn MessageInterruptController>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum PciDeviceState {
|
||||
None,
|
||||
Probed,
|
||||
Initialized,
|
||||
Failed,
|
||||
}
|
||||
|
||||
/// Used to store PCI bus devices which were enumerated by the kernel
|
||||
pub struct PciBusDevice {
|
||||
pub(crate) info: PciDeviceInfo,
|
||||
pub(crate) device: Option<Arc<dyn Device>>,
|
||||
pub(crate) driver_name: Option<&'static str>,
|
||||
pub(crate) driver: Option<&'static dyn PciDriver>,
|
||||
pub(crate) state: PciDeviceState,
|
||||
}
|
||||
|
||||
impl PciDeviceInfo {
|
||||
|
@ -12,7 +12,7 @@ use acpi::mcfg::McfgEntry;
|
||||
use alloc::{format, sync::Arc, vec::Vec};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use device::{PciBusDevice, PciDeviceInfo};
|
||||
use device::{PciBusDevice, PciDeviceInfo, PciDeviceState};
|
||||
use device_api::{device::DeviceInitContext, dma::DmaAllocator};
|
||||
use interrupt::{PciInterruptMap, PciMsiMap};
|
||||
use libk::{
|
||||
@ -386,8 +386,9 @@ impl PciBusSegment {
|
||||
|
||||
let object = nodes::make_sysfs_object(PciBusDevice {
|
||||
info,
|
||||
driver_name: None,
|
||||
driver: None,
|
||||
device: None,
|
||||
state: PciDeviceState::None,
|
||||
});
|
||||
let pci_object = PCI_SYSFS_NODE.or_init_with(|| {
|
||||
let bus_object = sysfs::bus().unwrap();
|
||||
@ -439,11 +440,16 @@ 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");
|
||||
pub fn probe_bus_devices() -> Result<(), Error> {
|
||||
Self::walk_bus_devices(|device| {
|
||||
// log::info!("Set up {}", device.info.address);
|
||||
setup_bus_device(device)?;
|
||||
probe_bus_device(device, false)?;
|
||||
Ok(true)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn setup_bus_devices(rescan: bool) -> Result<(), Error> {
|
||||
Self::walk_bus_devices(|device| {
|
||||
setup_bus_device(device, rescan)?;
|
||||
Ok(true)
|
||||
})
|
||||
}
|
||||
@ -611,28 +617,25 @@ impl PciConfigurationSpace for PciConfigSpace {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_bus_device(device: &mut PciBusDevice) -> Result<(), Error> {
|
||||
if device.device.is_some() {
|
||||
fn probe_bus_device(device: &mut PciBusDevice, _rescan: bool) -> Result<(), Error> {
|
||||
// Already has a driver/device set up
|
||||
if device.device.is_some() || device.state != PciDeviceState::None {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(driver) = driver::lookup_driver(&device.info) {
|
||||
log::info!("{} -> {}", device.info.address, driver.driver_name());
|
||||
let dma: Arc<dyn DmaAllocator> = Arc::new(DummyDmaAllocator);
|
||||
let cx = DeviceInitContext {
|
||||
dma_allocator: dma.clone(),
|
||||
};
|
||||
|
||||
match driver.probe(&device.info, &dma) {
|
||||
Ok(instance) => {
|
||||
unsafe { instance.clone().init(cx) }?;
|
||||
|
||||
log::info!("{} -> {}", device.info.address, driver.driver_name());
|
||||
device.device.replace(instance);
|
||||
device.driver_name.replace(driver.driver_name());
|
||||
device.driver.replace(driver);
|
||||
device.state = PciDeviceState::Probed;
|
||||
}
|
||||
Err(error) => {
|
||||
log::error!(
|
||||
"{} ({}): {error:?}",
|
||||
"{} ({}) probe error: {error:?}",
|
||||
device.info.address,
|
||||
driver.driver_name()
|
||||
);
|
||||
@ -643,5 +646,37 @@ fn setup_bus_device(device: &mut PciBusDevice) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_bus_device(device: &mut PciBusDevice, _rescan: bool) -> Result<(), Error> {
|
||||
// No driver yet (TODO probe if rescan is asked)
|
||||
let (Some(dev), Some(driver)) = (device.device.as_ref(), device.driver) else {
|
||||
return Ok(());
|
||||
};
|
||||
// Already initialized/failed
|
||||
if device.state != PciDeviceState::Probed {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let dma: Arc<dyn DmaAllocator> = Arc::new(DummyDmaAllocator);
|
||||
let cx = DeviceInitContext {
|
||||
dma_allocator: dma.clone(),
|
||||
};
|
||||
|
||||
match unsafe { dev.clone().init(cx) } {
|
||||
Ok(()) => {
|
||||
device.state = PciDeviceState::Initialized;
|
||||
}
|
||||
Err(error) => {
|
||||
log::error!(
|
||||
"{} ({}) setup error: {error:?}",
|
||||
device.info.address,
|
||||
driver.driver_name()
|
||||
);
|
||||
device.state = PciDeviceState::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
static PCI_MANAGER: IrqSafeSpinlock<PciBusManager> = IrqSafeSpinlock::new(PciBusManager::new());
|
||||
static PCI_SYSFS_NODE: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
|
||||
|
@ -25,7 +25,7 @@ pub(crate) fn make_sysfs_object(
|
||||
|
||||
fn read(state: &Self::Data) -> Result<String, Error> {
|
||||
let state = state.lock();
|
||||
if let Some(driver) = state.driver_name {
|
||||
if let Some(driver) = state.driver.map(|driver| driver.driver_name()) {
|
||||
Ok(driver.into())
|
||||
} else {
|
||||
Ok("".into())
|
||||
|
@ -1,6 +1,11 @@
|
||||
//! Ethernet PHY utilities
|
||||
|
||||
use libk::error::Error;
|
||||
use core::time::Duration;
|
||||
|
||||
use libk::{
|
||||
error::Error,
|
||||
task::runtime::{psleep, pwait_try},
|
||||
};
|
||||
use yggdrasil_abi::bitflags;
|
||||
|
||||
bitflags! {
|
||||
@ -77,6 +82,8 @@ pub struct PhyAccess<'a, M: MdioBus> {
|
||||
|
||||
pub const REG_BMCR: u8 = 0x00;
|
||||
pub const REG_BMSR: u8 = 0x01;
|
||||
pub const REG_PHYAD1: u8 = 0x02;
|
||||
pub const REG_PHYAD2: u8 = 0x03;
|
||||
pub const REG_ANAR: u8 = 0x04;
|
||||
pub const REG_GBCR: u8 = 0x09;
|
||||
pub const REG_GBESR: u8 = 0x0F;
|
||||
@ -105,18 +112,17 @@ impl<'a, M: MdioBus> PhyAccess<'a, M> {
|
||||
self.read_reg(REG_BMSR).map(BMSR::from)
|
||||
}
|
||||
|
||||
pub fn reset(&self, mut timeout: u64) -> Result<(), Error> {
|
||||
self.write_reg(REG_BMCR, BMCR::RESET.bits())?;
|
||||
while timeout > 0 && self.read_reg(REG_BMCR)? & BMCR::RESET.bits() != 0 {
|
||||
core::hint::spin_loop();
|
||||
timeout -= 1;
|
||||
}
|
||||
pub fn id(&self) -> Result<(u16, u16), Error> {
|
||||
let id0 = self.read_reg(REG_PHYAD1)?;
|
||||
let id1 = self.read_reg(REG_PHYAD2)?;
|
||||
Ok((id0, id1))
|
||||
}
|
||||
|
||||
if timeout > 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::TimedOut)
|
||||
}
|
||||
pub fn reset(&self, timeout: Duration) -> Result<(), Error> {
|
||||
self.write_reg(REG_BMCR, BMCR::RESET.bits())?;
|
||||
pwait_try(timeout, Duration::from_millis(10), || {
|
||||
Ok(self.read_reg(REG_BMCR)? & BMCR::RESET.bits() == 0)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn setup_link(&self, have_pause: bool, force_gbesr: GBESR) -> Result<(), Error> {
|
||||
@ -140,19 +146,13 @@ impl<'a, M: MdioBus> PhyAccess<'a, M> {
|
||||
}
|
||||
|
||||
self.write_reg(REG_ANAR, anar.bits())?;
|
||||
for _ in 0..10000000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
psleep(Duration::from_millis(10));
|
||||
|
||||
self.write_reg(REG_GBCR, gbcr.bits())?;
|
||||
for _ in 0..10000000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
psleep(Duration::from_millis(10));
|
||||
|
||||
self.write_reg(REG_BMCR, (BMCR::ANE | BMCR::RESTART_AN).bits())?;
|
||||
for _ in 0..10000000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
psleep(Duration::from_millis(10));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use core::{fmt, mem::size_of};
|
||||
use core::mem::size_of;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use bytemuck::Pod;
|
||||
|
@ -9,7 +9,7 @@ use core::mem::size_of;
|
||||
use alloc::sync::Arc;
|
||||
use bytemuck::Pod;
|
||||
use ethernet::L2Packet;
|
||||
use interface::{NetworkDevice, NetworkInterface};
|
||||
use interface::NetworkInterface;
|
||||
use l3::L3Packet;
|
||||
use libk::{dma::DmaBuffer, task::runtime};
|
||||
use libk_util::queue::UnboundedMpmcQueue;
|
||||
@ -39,6 +39,7 @@ pub struct TxPacketBuilder<'a> {
|
||||
nic: &'a NetworkInterface,
|
||||
data: DmaBuffer<[u8]>,
|
||||
pos: usize,
|
||||
#[allow(unused)]
|
||||
l2_offset: usize,
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ impl TxRing {
|
||||
buffer.len() as u16 - 4,
|
||||
index % quarter == quarter - 1,
|
||||
);
|
||||
self.descriptors.cache_flush_element(index);
|
||||
self.descriptors.cache_flush_element(index, true);
|
||||
|
||||
self.buffers[index] = Some(buffer);
|
||||
|
||||
|
@ -15,3 +15,4 @@ ygg_driver_net_core.path = "../core"
|
||||
|
||||
tock-registers.workspace = true
|
||||
log.workspace = true
|
||||
futures-util.workspace = true
|
||||
|
@ -61,6 +61,9 @@ pci_driver! {
|
||||
}
|
||||
|
||||
fn probe(&self, info: &PciDeviceInfo, dma: &Arc<dyn DmaAllocator>) -> Result<Arc<dyn Device>, Error> {
|
||||
// Enable MMIO + interrupts + bus mastering
|
||||
info.set_command(false, true, true, true);
|
||||
|
||||
let base = info
|
||||
.config_space
|
||||
.bar(2)
|
||||
@ -69,10 +72,14 @@ pci_driver! {
|
||||
|
||||
if let Some(power) = info.config_space.capability::<PowerManagementCapability>() {
|
||||
power.set_device_power_state(DevicePowerState::D0);
|
||||
power.set_pme_en(true);
|
||||
}
|
||||
|
||||
// Enable MMIO + interrupts + bus mastering
|
||||
info.set_command(true, true, false, true);
|
||||
if let Some(mut pcie) = info.config_space.capability::<PciExpressCapability>() {
|
||||
let mut lcr = pcie.link_control();
|
||||
lcr.remove(PcieLinkControl::ASPM_MASK | PcieLinkControl::ECPM);
|
||||
pcie.set_link_control(lcr);
|
||||
}
|
||||
|
||||
let device = Rtl8168::new(dma.clone(), base, info.clone())?;
|
||||
Ok(Arc::new(device))
|
||||
|
@ -1,6 +1,7 @@
|
||||
use core::{
|
||||
mem::{self, MaybeUninit},
|
||||
sync::atomic::{self, Ordering},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
@ -9,16 +10,19 @@ use device_api::{
|
||||
dma::DmaAllocator,
|
||||
interrupt::{InterruptHandler, IrqVector},
|
||||
};
|
||||
use futures_util::task::AtomicWaker;
|
||||
use libk::{
|
||||
dma::{BusAddress, DmaBuffer},
|
||||
error::Error,
|
||||
task::runtime::{self, psleep, pwait},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo, L3_PAGE_SIZE};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use libk_util::{event::BitmapEvent, sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use tock_registers::{
|
||||
interfaces::{ReadWriteable, Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::{ReadOnly, ReadWrite, WriteOnly},
|
||||
LocalRegisterCopy,
|
||||
};
|
||||
use ygg_driver_net_core::{
|
||||
ephy::{MdioBus, PhyAccess, GBESR},
|
||||
@ -37,6 +41,8 @@ use yggdrasil_abi::{
|
||||
register_bitfields! {
|
||||
u8,
|
||||
CR [
|
||||
/// Request the MAC to stop its Tx/Rx activity
|
||||
STOP OFFSET(7) NUMBITS(1) [],
|
||||
/// Software reset bit. Set by driver, cleared by device
|
||||
RST OFFSET(4) NUMBITS(1) [],
|
||||
/// Rx enable
|
||||
@ -117,7 +123,8 @@ register_bitfields! {
|
||||
IFG OFFSET(24) NUMBITS(2) [],
|
||||
HWVERID2 OFFSET(23) NUMBITS(1) [],
|
||||
TX_NOCRC OFFSET(16) NUMBITS(1) [],
|
||||
MXDMA OFFSET(8) NUMBITS(1) [
|
||||
QUEUE_EMPTY OFFSET(11) NUMBITS(1) [],
|
||||
MXDMA OFFSET(8) NUMBITS(3) [
|
||||
Burst16 = 0b000,
|
||||
Burst32 = 0b001,
|
||||
Burst64 = 0b010,
|
||||
@ -228,7 +235,7 @@ bitflags! {
|
||||
enum Revision {
|
||||
rtl8168gu,
|
||||
rtl8168h,
|
||||
other,
|
||||
other(u32),
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -260,6 +267,8 @@ pub struct Rtl8168 {
|
||||
rx: OneTimeInit<IrqSafeSpinlock<RxRing>>,
|
||||
tx: OneTimeInit<IrqSafeSpinlock<TxRing>>,
|
||||
|
||||
events: BitmapEvent<AtomicWaker>,
|
||||
|
||||
dma: Arc<dyn DmaAllocator>,
|
||||
}
|
||||
|
||||
@ -334,6 +343,7 @@ impl TxRing {
|
||||
pub fn push(&mut self, packet: DmaBuffer<[u8]>) -> Result<(), Error> {
|
||||
let packet_base = packet.bus_address();
|
||||
let packet_size = packet.len();
|
||||
let capacity = self.entries.len();
|
||||
|
||||
// TODO packet size checks
|
||||
|
||||
@ -342,9 +352,13 @@ impl TxRing {
|
||||
return Err(Error::WouldBlock);
|
||||
}
|
||||
|
||||
let index = self.wr % self.entries.len();
|
||||
let index = self.wr % capacity;
|
||||
packet.cache_flush_all(true);
|
||||
self.buffers[index] = Some(packet);
|
||||
self.entries[index].setup_tx(packet_base, packet_size);
|
||||
self.entries[index].setup_tx(packet_base, packet_size, index == capacity - 1);
|
||||
self.entries.cache_flush_element(index, true);
|
||||
self.entries[index].cmd |= Descriptor::CMD_OWN;
|
||||
self.entries.cache_flush_element(index, true);
|
||||
|
||||
self.wr = self.wr.wrapping_add(1);
|
||||
|
||||
@ -413,15 +427,14 @@ impl Descriptor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_tx(&mut self, buffer: BusAddress, size: usize) {
|
||||
let mut cmd = self.cmd;
|
||||
cmd |= Self::CMD_OWN | Self::CMD_FS | Self::CMD_LS | (size as u32);
|
||||
pub fn setup_tx(&mut self, buffer: BusAddress, size: usize, last: bool) {
|
||||
let mut cmd = Self::CMD_FS | Self::CMD_LS | (size as u32);
|
||||
if last {
|
||||
cmd |= Self::CMD_END;
|
||||
}
|
||||
self.address = buffer;
|
||||
self.vlan_cmd = 0;
|
||||
unsafe {
|
||||
atomic::fence(Ordering::Release);
|
||||
core::ptr::write_volatile(&mut self.cmd, cmd);
|
||||
}
|
||||
self.cmd = cmd;
|
||||
}
|
||||
|
||||
pub fn is_host_owned(&self) -> bool {
|
||||
@ -462,74 +475,78 @@ impl Regs {
|
||||
match rev {
|
||||
0x50800000 => Revision::rtl8168gu,
|
||||
0x54000000 => Revision::rtl8168h,
|
||||
_ => Revision::other,
|
||||
_ => Revision::other(rev),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_device(&self, mut timeout: u64) -> Result<(), Error> {
|
||||
pub fn reset_device(&self, timeout: Duration) -> Result<(), Error> {
|
||||
self.CR.write(CR::RST::SET);
|
||||
|
||||
for _ in 0..100000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
|
||||
while timeout > 0 && self.CR.matches_all(CR::RST::SET) {
|
||||
core::hint::spin_loop();
|
||||
timeout -= 1;
|
||||
}
|
||||
|
||||
if timeout == 0 {
|
||||
Err(Error::TimedOut)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
psleep(Duration::from_millis(10));
|
||||
pwait(timeout, Duration::from_millis(10), || {
|
||||
self.CR.matches_all(CR::RST::CLEAR)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn reset_phy(&self, timeout: u64) -> Result<(), Error> {
|
||||
pub fn reset_phy(&self, timeout: Duration) -> Result<(), Error> {
|
||||
let phy = PhyAccess::new(self, 0x00);
|
||||
|
||||
let (id0, id1) = phy.id()?;
|
||||
log::info!("PHY {id0:04x}:{id1:04x}");
|
||||
|
||||
phy.write_reg(0x1F, 0x00)?;
|
||||
phy.write_reg(0x0E, 0x00)?;
|
||||
|
||||
phy.reset(timeout)?;
|
||||
phy.setup_link(true, GBESR::empty())?;
|
||||
|
||||
psleep(Duration::from_millis(100));
|
||||
|
||||
phy.write_reg(0x1F, 0x00)?;
|
||||
phy.write_reg(0x0E, 0x00)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stop(&self, timeout: Duration) -> Result<(), Error> {
|
||||
self.CR.write(CR::STOP::SET);
|
||||
|
||||
pwait(timeout, Duration::from_millis(10), || {
|
||||
self.TCR.matches_all(TCR::QUEUE_EMPTY::SET)
|
||||
})?;
|
||||
|
||||
psleep(Duration::from_millis(100));
|
||||
|
||||
self.IMR.set(0x0000);
|
||||
self.ISR.set(0xFFFF);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl MdioBus for Regs {
|
||||
fn mii_read(&self, _phyaddr: u8, reg: u8) -> Result<u16, Error> {
|
||||
let mut timeout = 1000000;
|
||||
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;
|
||||
}
|
||||
psleep(Duration::from_millis(10));
|
||||
pwait(
|
||||
Duration::from_millis(100),
|
||||
Duration::from_millis(10),
|
||||
|| self.PHYAR.matches_all(PHYAR::FLAG::SET),
|
||||
)?;
|
||||
Ok(self.PHYAR.read(PHYAR::DATA) as u16)
|
||||
}
|
||||
|
||||
fn mii_write(&self, _phyaddr: u8, reg: u8, value: u16) -> Result<(), Error> {
|
||||
let mut timeout = 1000000;
|
||||
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(())
|
||||
}
|
||||
psleep(Duration::from_millis(10));
|
||||
pwait(
|
||||
Duration::from_millis(100),
|
||||
Duration::from_millis(10),
|
||||
|| self.PHYAR.matches_all(PHYAR::FLAG::CLEAR),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -552,6 +569,8 @@ impl Rtl8168 {
|
||||
rx: OneTimeInit::new(),
|
||||
tx: OneTimeInit::new(),
|
||||
|
||||
events: BitmapEvent::new(AtomicWaker::new()),
|
||||
|
||||
dma,
|
||||
})
|
||||
}
|
||||
@ -560,48 +579,57 @@ impl Rtl8168 {
|
||||
impl InterruptHandler for Rtl8168 {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let regs = self.regs.lock();
|
||||
|
||||
let status = regs.ISR.extract();
|
||||
|
||||
if status.get() == 0 {
|
||||
if status.get() == 0 || status.get() == 0xFFFF {
|
||||
return false;
|
||||
}
|
||||
log::info!("RTL8168 IRQ");
|
||||
|
||||
regs.IMR.set(0x0000);
|
||||
// Acknowledge interrupt
|
||||
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(&*self.dma, |buffer| {
|
||||
// Forward to softirq
|
||||
self.events.signal(status.get() as u64);
|
||||
|
||||
// Restore interrupt mask
|
||||
regs.IMR.set(0xFFFF);
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Rtl8168 {
|
||||
// "softirq" handler for rtl8168
|
||||
async fn packet_handler(&self) {
|
||||
let nic = *self.nic.get();
|
||||
let tx = self.tx.get();
|
||||
let rx = self.rx.get();
|
||||
|
||||
loop {
|
||||
let events = LocalRegisterCopy::new(self.events.wait().await as u16);
|
||||
|
||||
if events.matches_all(IMR_ISR::LINKCHG::SET) {
|
||||
let status = self.link_state();
|
||||
log::info!("rtl8168: link is {status}");
|
||||
}
|
||||
|
||||
if events.matches_all(IMR_ISR::ROK::SET) {
|
||||
let mut rx = rx.lock();
|
||||
rx.consume(&*self.dma, |buffer| {
|
||||
// TODO add packet len hint to packets
|
||||
let packet = RxPacket::new(buffer, 0, nic);
|
||||
ygg_driver_net_core::receive_packet(packet).ok();
|
||||
})
|
||||
.unwrap_or(0);
|
||||
.ok();
|
||||
}
|
||||
|
||||
any |= count != 0;
|
||||
if events.matches_all(IMR_ISR::TOK::SET) {
|
||||
let mut tx = tx.lock();
|
||||
tx.consume().ok();
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -612,53 +640,55 @@ impl Device for Rtl8168 {
|
||||
|
||||
// Bind IRQ
|
||||
self.pci
|
||||
.init_interrupts(PreferredInterruptMode::Msi(false))?;
|
||||
.init_interrupts(PreferredInterruptMode::Msi(true))?;
|
||||
let msi_info = self.pci.map_interrupt(Default::default(), self.clone())?;
|
||||
if msi_info.is_none() {
|
||||
log::error!("rtl8168 in non-MSI(-x) mode is not supported yet");
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
|
||||
let regs = self.regs.lock();
|
||||
|
||||
regs.R9346CR.write(R9346CR::EEM::ConfigWriteEnable);
|
||||
if msi_info.is_some() {
|
||||
log::info!("Switch rtl816x into MSI(-x) mode");
|
||||
regs.CONFIG2.modify(CONFIG2::MSI::SET);
|
||||
} else {
|
||||
log::info!("Switch rtl816x into legacy IRQ mode");
|
||||
regs.CONFIG2.modify(CONFIG2::MSI::CLEAR);
|
||||
let hwrev = regs.get_chip_revision();
|
||||
|
||||
if let Revision::other(id) = hwrev {
|
||||
log::error!("rtl8168: unsupported chip ID {:#08x}, aborting", id);
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
|
||||
regs.R9346CR.write(R9346CR::EEM::ConfigWriteEnable);
|
||||
regs.CONFIG2.modify(CONFIG2::MSI::SET);
|
||||
regs.R9346CR.write(R9346CR::EEM::Normal);
|
||||
|
||||
let rx_ring = RxRing::with_capacity(&*self.dma, 256)?;
|
||||
let tx_ring = TxRing::with_capacity(&*self.dma, 256)?;
|
||||
let rx_ring = RxRing::with_capacity(&*self.dma, 1024)?;
|
||||
let tx_ring = TxRing::with_capacity(&*self.dma, 1024)?;
|
||||
let rx_ring_base = rx_ring.base_address().into_u64();
|
||||
let tx_ring_base = tx_ring.base_address().into_u64();
|
||||
|
||||
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"))?;
|
||||
// If the MAC was performing any I/O prior to driver init, stop it
|
||||
regs.stop(Duration::from_secs(1))?;
|
||||
|
||||
// Perform software reset
|
||||
regs.reset_device(Duration::from_millis(100))?;
|
||||
|
||||
// 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);
|
||||
|
||||
regs.IMR.set(0x0000);
|
||||
regs.ISR.set(0xFFFF);
|
||||
|
||||
// Reset the PHY
|
||||
if flags.contains(ChipFlags::NEED_PHY_RESET) {
|
||||
regs.reset_phy(10000000)
|
||||
.inspect_err(|_| log::warn!("rtl81xx: PHY reset timed out"))?;
|
||||
log::info!("Reset PHY and start AN");
|
||||
regs.reset_phy(Duration::from_millis(1000))?;
|
||||
}
|
||||
|
||||
// TODO initialize MAC address
|
||||
|
||||
//regs.R9346CR.write(R9346CR::EEM::Normal);
|
||||
|
||||
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);
|
||||
@ -668,38 +698,30 @@ impl Device for Rtl8168 {
|
||||
regs.MISC.set(regs.MISC.get() & !0x80000);
|
||||
}
|
||||
|
||||
log::info!("rx_ring_base = {rx_ring_base:#x}");
|
||||
|
||||
// Setup Tx
|
||||
regs.TCR.modify(TCR::MXDMA::Unlimited);
|
||||
regs.TCR.modify(TCR::MXDMA::Unlimited + TCR::IFG.val(3));
|
||||
// Setup Rx
|
||||
regs.MTPS.set(16);
|
||||
let mut rcr = RCR::MXDMA::Unlimited
|
||||
+ RCR::RXFTH::NoThreshold
|
||||
+ RCR::AAP::SET
|
||||
+ RCR::AB::SET
|
||||
+ RCR::AM::SET
|
||||
+ RCR::APM::SET;
|
||||
if flags.contains(ChipFlags::EARLYOFFV2) {
|
||||
rcr += RCR::EARLYOFFV2::SET;
|
||||
}
|
||||
regs.RCR.write(rcr);
|
||||
regs.RCR.set(rcr.value | 0x1800);
|
||||
|
||||
// Enable Rx/Tx
|
||||
regs.CR.write(CR::RE::SET + CR::TE::SET);
|
||||
|
||||
// Setup interrupts
|
||||
// regs.IMR.set(0xFFFF);
|
||||
regs.IMR.write(
|
||||
IMR_ISR::RDU::SET + IMR_ISR::ROK::SET + IMR_ISR::TOK::SET + IMR_ISR::LINKCHG::SET,
|
||||
);
|
||||
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);
|
||||
regs.RMS.set(4096);
|
||||
|
||||
self.rx.init(IrqSafeSpinlock::new(rx_ring));
|
||||
self.tx.init(IrqSafeSpinlock::new(tx_ring));
|
||||
@ -708,6 +730,11 @@ impl Device for Rtl8168 {
|
||||
ygg_driver_net_core::register_interface(NetworkInterfaceType::Ethernet, self.clone());
|
||||
self.nic.init(interface.id());
|
||||
|
||||
drop(regs);
|
||||
|
||||
let this = self.clone();
|
||||
runtime::spawn(async move { this.packet_handler().await })?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -725,6 +752,10 @@ impl NetworkDevice for Rtl8168 {
|
||||
let mut tx = self.tx.get().lock();
|
||||
let regs = self.regs.lock();
|
||||
|
||||
if !matches!(regs.get_link_state(), EthernetLinkState::Up(_, _)) {
|
||||
return Err(Error::NetworkUnreachable);
|
||||
}
|
||||
|
||||
tx.push(buffer)?;
|
||||
regs.TPPOLL.write(TPPOLL::NPQ::SET);
|
||||
|
||||
@ -753,7 +784,7 @@ impl Revision {
|
||||
| ChipFlags::RXDV_GATED
|
||||
| ChipFlags::EARLYOFFV2
|
||||
}
|
||||
Self::other => ChipFlags::empty(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -496,10 +496,18 @@ impl<T> DerefMut for PageSlice<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush_cache_data<T>(data: *const T) {
|
||||
pub fn flush_cache_data<T>(data: *const T, write: bool) {
|
||||
if write {
|
||||
ArchitectureImpl::store_barrier();
|
||||
}
|
||||
ArchitectureImpl::flush_virtual_range(data.addr()..data.addr() + size_of::<T>());
|
||||
ArchitectureImpl::memory_barrier();
|
||||
}
|
||||
|
||||
pub fn flush_cache_data_slice<T>(data: *const [T]) {
|
||||
pub fn flush_cache_data_slice<T>(data: *const [T], write: bool) {
|
||||
if write {
|
||||
ArchitectureImpl::store_barrier();
|
||||
}
|
||||
ArchitectureImpl::flush_virtual_range(data.addr()..data.addr() + size_of::<T>() * data.len());
|
||||
ArchitectureImpl::memory_barrier();
|
||||
}
|
||||
|
@ -1,17 +1,45 @@
|
||||
use core::{
|
||||
future::poll_fn,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
task::{Context, Poll},
|
||||
sync::atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
task::{Context, Poll, Waker},
|
||||
};
|
||||
|
||||
use futures_util::task::AtomicWaker;
|
||||
|
||||
use crate::{sync::spin_rwlock::IrqSafeRwLock, waker::QueueWaker};
|
||||
|
||||
pub trait EventNotify: Sync {
|
||||
fn subscribe(&self, waker: &Waker);
|
||||
fn unsubscribe(&self, waker: &Waker);
|
||||
fn notify_one(&self);
|
||||
fn notify_all(&self);
|
||||
}
|
||||
|
||||
impl EventNotify for AtomicWaker {
|
||||
fn subscribe(&self, waker: &Waker) {
|
||||
self.register(waker);
|
||||
}
|
||||
fn unsubscribe(&self, _waker: &Waker) {}
|
||||
|
||||
fn notify_one(&self) {
|
||||
self.wake();
|
||||
}
|
||||
fn notify_all(&self) {
|
||||
self.wake();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OneTimeEvent<T> {
|
||||
// TODO lockless like OneTimeInit?
|
||||
value: IrqSafeRwLock<Option<T>>,
|
||||
notify: QueueWaker,
|
||||
}
|
||||
|
||||
pub struct BitmapEvent<N: EventNotify> {
|
||||
value: AtomicU64,
|
||||
notify: N,
|
||||
}
|
||||
|
||||
pub struct BoolEvent {
|
||||
state: AtomicBool,
|
||||
notify: QueueWaker,
|
||||
@ -162,3 +190,31 @@ impl BoolEvent {
|
||||
poll_fn(|cx| self.poll(cx)).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: EventNotify> BitmapEvent<N> {
|
||||
pub const fn new(notify: N) -> Self {
|
||||
Self {
|
||||
value: AtomicU64::new(0),
|
||||
notify,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal(&self, mask: u64) {
|
||||
self.value.fetch_or(mask, Ordering::Release);
|
||||
self.notify.notify_all();
|
||||
}
|
||||
|
||||
pub async fn wait(&self) -> u64 {
|
||||
poll_fn(|cx| {
|
||||
let state = self.value.swap(0, Ordering::AcqRel);
|
||||
if state != 0 {
|
||||
self.notify.unsubscribe(cx.waker());
|
||||
Poll::Ready(state)
|
||||
} else {
|
||||
self.notify.subscribe(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
@ -214,16 +214,16 @@ impl<T> DmaBuffer<[T]> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cache_flush_element(&self, index: usize) {
|
||||
libk_mm::flush_cache_data(&raw const self[index]);
|
||||
pub fn cache_flush_element(&self, index: usize, write: bool) {
|
||||
libk_mm::flush_cache_data(&raw const self[index], write);
|
||||
}
|
||||
|
||||
pub fn cache_flush_range(&self, range: Range<usize>) {
|
||||
libk_mm::flush_cache_data_slice(&raw const self[range]);
|
||||
pub fn cache_flush_range(&self, range: Range<usize>, write: bool) {
|
||||
libk_mm::flush_cache_data_slice(&raw const self[range], write);
|
||||
}
|
||||
|
||||
pub fn cache_flush_all(&self) {
|
||||
libk_mm::flush_cache_data_slice(&raw const self[..]);
|
||||
pub fn cache_flush_all(&self, write: bool) {
|
||||
libk_mm::flush_cache_data_slice(&raw const self[..], write);
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,8 +321,8 @@ impl<'a, T> DmaSlice<'a, T> {
|
||||
(self.buffer, self.range)
|
||||
}
|
||||
|
||||
pub fn cache_flush_all(&self) {
|
||||
self.buffer.cache_flush_range(self.range.clone());
|
||||
pub fn cache_flush_all(&self, write: bool) {
|
||||
self.buffer.cache_flush_range(self.range.clone(), write);
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,8 +350,8 @@ impl<'a, T> DmaSliceMut<'a, T> {
|
||||
(self.buffer, self.range)
|
||||
}
|
||||
|
||||
pub fn cache_flush_all(&self) {
|
||||
self.buffer.cache_flush_range(self.range.clone());
|
||||
pub fn cache_flush_all(&self, write: bool) {
|
||||
self.buffer.cache_flush_range(self.range.clone(), write);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,4 +8,6 @@ mod timer;
|
||||
|
||||
pub use executor::{run_to_completion, spawn, spawn_async_worker};
|
||||
pub use task_queue::init_task_queue;
|
||||
pub use timer::{maybe_timeout, sleep, sleep_until, tick, with_timeout, SleepFuture};
|
||||
pub use timer::{
|
||||
maybe_timeout, psleep, pwait, pwait_try, sleep, sleep_until, tick, with_timeout, SleepFuture,
|
||||
};
|
||||
|
@ -7,6 +7,7 @@ use core::{
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use futures_util::{Future, FutureExt};
|
||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use yggdrasil_abi::{error::Error, time::SystemTime};
|
||||
|
||||
@ -121,6 +122,85 @@ pub fn sleep_until(deadline: SystemTime) -> SleepFuture {
|
||||
SleepFuture { deadline }
|
||||
}
|
||||
|
||||
/// Wait for at least a certain duration has passed.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This function unmasks IRQs. Do not use it where interrupts can break something.
|
||||
pub fn psleep(duration: Duration) {
|
||||
// Unlock IRQs here, otherwise no timer events will be received and monotonic_time() will stay
|
||||
// the same
|
||||
let now = monotonic_time();
|
||||
let deadline = now + duration;
|
||||
|
||||
let old_irq_mask = ArchitectureImpl::interrupt_mask();
|
||||
unsafe { ArchitectureImpl::set_interrupt_mask(false) };
|
||||
|
||||
while monotonic_time() < deadline {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
|
||||
// Restore IRQ mask
|
||||
unsafe { ArchitectureImpl::set_interrupt_mask(old_irq_mask) };
|
||||
}
|
||||
|
||||
/// Wait for some condition to become true, or for the timeout to expire.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * [Error::TimedOut] if the condition didn't become `true` within a given deadline.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This function unmasks IRQs. Do not use it where interrupts can break something.
|
||||
pub fn pwait<P: Fn() -> bool>(
|
||||
timeout: Duration,
|
||||
poll_rate: Duration,
|
||||
predicate: P,
|
||||
) -> Result<(), Error> {
|
||||
let now = monotonic_time();
|
||||
let deadline = now + timeout;
|
||||
|
||||
loop {
|
||||
if predicate() {
|
||||
return Ok(());
|
||||
}
|
||||
if monotonic_time() > deadline {
|
||||
return Err(Error::TimedOut);
|
||||
}
|
||||
psleep(poll_rate);
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait for some condition to become true, fail, or for the timeout to expire.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * [Error] if the predicate returns an error.
|
||||
/// * [Error::TimedOut] if the condition didn't become `true` within a given deadline.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This function unmasks IRQs. Do not use it where interrupts can break something.
|
||||
pub fn pwait_try<P: Fn() -> Result<bool, Error>>(
|
||||
timeout: Duration,
|
||||
poll_rate: Duration,
|
||||
predicate: P,
|
||||
) -> Result<(), Error> {
|
||||
let now = monotonic_time();
|
||||
let deadline = now + timeout;
|
||||
|
||||
loop {
|
||||
if predicate()? {
|
||||
return Ok(());
|
||||
}
|
||||
if monotonic_time() > deadline {
|
||||
return Err(Error::TimedOut);
|
||||
}
|
||||
psleep(poll_rate);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_timeout<'a, T: 'a, F: Future<Output = T> + Send + 'a>(
|
||||
fut: F,
|
||||
timeout: Duration,
|
||||
|
@ -296,7 +296,7 @@ impl AArch64 {
|
||||
},
|
||||
);
|
||||
|
||||
PciBusManager::setup_bus_devices()?;
|
||||
PciBusManager::probe_bus_devices()?;
|
||||
} else {
|
||||
// BSP already initialized everything needed
|
||||
// Setup timer and local interrupt controller
|
||||
|
@ -236,7 +236,7 @@ impl Riscv64 {
|
||||
},
|
||||
);
|
||||
|
||||
PciBusManager::setup_bus_devices()?;
|
||||
PciBusManager::probe_bus_devices()?;
|
||||
}
|
||||
|
||||
// TODO more granular control over how U-mode pages are accessed from S-mode
|
||||
|
@ -134,7 +134,7 @@ pub fn init_platform_devices(early: EarlyPlatformDevices) {
|
||||
log::error!("COM port IRQ init error: {error:?}");
|
||||
}
|
||||
|
||||
if let Err(error) = PciBusManager::setup_bus_devices() {
|
||||
if let Err(error) = PciBusManager::probe_bus_devices() {
|
||||
log::error!("PCI bus device setup error(s): {error:?}");
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Kernel main process implementation: filesystem initialization and userspace init start
|
||||
|
||||
use abi::error::Error;
|
||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||
use libk::{
|
||||
device::display::console,
|
||||
fs::devfs,
|
||||
@ -9,6 +10,7 @@ use libk::{
|
||||
vfs::{impls::fn_hardlink, IoContext, NodeRef, OwnedFilename},
|
||||
};
|
||||
use memfs::MemoryFilesystem;
|
||||
use ygg_driver_pci::PciBusManager;
|
||||
|
||||
use crate::{
|
||||
fs::{FileBlockAllocator, INITRD_DATA},
|
||||
@ -28,8 +30,15 @@ fn setup_root() -> Result<NodeRef, Error> {
|
||||
/// This function is meant to be used as a kernel-space process after all the platform-specific
|
||||
/// initialization has finished.
|
||||
pub fn kinit() -> Result<(), Error> {
|
||||
assert!(!ArchitectureImpl::interrupt_mask());
|
||||
log::info!("In main");
|
||||
|
||||
// Initialize PCI devices
|
||||
if let Err(error) = PciBusManager::setup_bus_devices(false) {
|
||||
log::error!("pci bus setup error: {error:?}");
|
||||
}
|
||||
assert!(!ArchitectureImpl::interrupt_mask());
|
||||
|
||||
runtime::spawn(ygg_driver_usb::bus::bus_handler())?;
|
||||
runtime::spawn(console::flush_consoles_task()).ok();
|
||||
|
||||
|
@ -89,7 +89,7 @@ fn resolve_routing(address: IpAddr) -> Result<PingRouting, Error> {
|
||||
todo!();
|
||||
};
|
||||
|
||||
let gateway_mac = nc.query_arp(routing.interface_id, gateway, true)?;
|
||||
let gateway_mac = nc.query_arp(routing.interface_id, gateway, false)?;
|
||||
|
||||
Ok(PingRouting {
|
||||
interface_id: routing.interface_id,
|
||||
|
Loading…
x
Reference in New Issue
Block a user