From 6966475dcf48b1607f53678eb3ebbe2efcd8e6bb Mon Sep 17 00:00:00 2001 From: Bananymous Date: Mon, 4 May 2026 21:15:15 +0300 Subject: [PATCH] Kernel: Make E1000 sending lockless and mostly non-blocking Now we only block if all 256 tx descriptors are waiting to be sent. This removes TCP acks from taking 30% of profiles while DOWNLOADING files --- .../include/kernel/Networking/E1000/E1000.h | 8 +++-- kernel/kernel/Networking/E1000/E1000.cpp | 30 +++++++++---------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/kernel/include/kernel/Networking/E1000/E1000.h b/kernel/include/kernel/Networking/E1000/E1000.h index 0135bb34..4e131b1a 100644 --- a/kernel/include/kernel/Networking/E1000/E1000.h +++ b/kernel/include/kernel/Networking/E1000/E1000.h @@ -73,11 +73,15 @@ namespace Kernel BAN::UniqPtr m_tx_buffer_region; BAN::UniqPtr m_rx_descriptor_region; BAN::UniqPtr m_tx_descriptor_region; - SpinLock m_lock; + + BAN::Atomic m_tx_head1 { 0 }; + BAN::Atomic m_tx_head2 { 0 }; + + SpinLock m_rx_lock; + ThreadBlocker m_rx_blocker; bool m_thread_should_die { false }; BAN::Atomic m_thread_is_dead { true }; - ThreadBlocker m_thread_blocker; BAN::MACAddress m_mac_address {}; bool m_link_up { false }; diff --git a/kernel/kernel/Networking/E1000/E1000.cpp b/kernel/kernel/Networking/E1000/E1000.cpp index 7534e76c..8923086b 100644 --- a/kernel/kernel/Networking/E1000/E1000.cpp +++ b/kernel/kernel/Networking/E1000/E1000.cpp @@ -59,7 +59,7 @@ namespace Kernel E1000::~E1000() { m_thread_should_die = true; - m_thread_blocker.unblock(); + m_rx_blocker.unblock(); while (!m_thread_is_dead) Processor::yield(); @@ -214,6 +214,7 @@ namespace Kernel for (size_t i = 0; i < E1000_TX_DESCRIPTOR_COUNT; i++) { tx_descriptors[i].addr = m_tx_buffer_region->paddr() + E1000_TX_BUFFER_SIZE * i; + tx_descriptors[i].status = 0xFF; /* NOTE: set status to non-zero so send_bytes doesn't think these are initially pending */ tx_descriptors[i].cmd = 0; } @@ -277,9 +278,11 @@ namespace Kernel BAN::ErrorOr E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span payload) { - SpinLockGuard _(m_lock); + const uint32_t tx_current = m_tx_head1.fetch_add(1) % E1000_TX_DESCRIPTOR_COUNT; - size_t tx_current = read32(REG_TDT) % E1000_TX_DESCRIPTOR_COUNT; + auto& descriptor = reinterpret_cast(m_tx_descriptor_region->vaddr())[tx_current]; + while (descriptor.status == 0) + Processor::yield(); auto* tx_buffer = reinterpret_cast(m_tx_buffer_region->vaddr() + E1000_TX_BUFFER_SIZE * tx_current); @@ -296,15 +299,12 @@ namespace Kernel packet_size += buffer.size(); } - auto& descriptor = reinterpret_cast(m_tx_descriptor_region->vaddr())[tx_current]; descriptor.length = packet_size; descriptor.status = 0; descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS; - // FIXME: there isnt really any reason to wait for transmission - write32(REG_TDT, (tx_current + 1) % E1000_TX_DESCRIPTOR_COUNT); - while (descriptor.status == 0) - Processor::pause(); + if (tx_current == m_tx_head2.fetch_add(1) % E1000_TX_DESCRIPTOR_COUNT) + write32(REG_TDT, (tx_current + 1) % E1000_TX_DESCRIPTOR_COUNT); dprintln_if(DEBUG_E1000, "sent {} bytes", packet_size); @@ -313,7 +313,7 @@ namespace Kernel void E1000::receive_thread() { - SpinLockGuard _(m_lock); + SpinLockGuard _(m_rx_lock); while (!m_thread_should_die) { @@ -328,21 +328,21 @@ namespace Kernel dprintln_if(DEBUG_E1000, "got {} bytes", (uint16_t)descriptor.length); - m_lock.unlock(InterruptState::Enabled); + m_rx_lock.unlock(InterruptState::Enabled); NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { reinterpret_cast(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE), descriptor.length }); - m_lock.lock(); + m_rx_lock.lock(); descriptor.status = 0; write32(REG_RDT0, rx_current); } - SpinLockAsMutex smutex(m_lock, InterruptState::Enabled); - m_thread_blocker.block_indefinite(&smutex); + SpinLockAsMutex smutex(m_rx_lock, InterruptState::Enabled); + m_rx_blocker.block_indefinite(&smutex); } m_thread_is_dead = true; @@ -355,8 +355,8 @@ namespace Kernel if (icr & (ICR_RxQ0 | ICR_RXT0)) { - SpinLockGuard _(m_lock); - m_thread_blocker.unblock(); + SpinLockGuard _(m_rx_lock); + m_rx_blocker.unblock(); } }