Kernel: Support hardware checksum offload on RTL8169 receive

This commit is contained in:
2026-06-29 01:17:51 +03:00
parent ddb7641b05
commit 4e28a35af9

View File

@@ -132,6 +132,10 @@ namespace Kernel
// configure max rx packet size // configure max rx packet size
m_io_bar_region->write16(RTL8169_IO_RMS, RTL8169_RMS_MAX); m_io_bar_region->write16(RTL8169_IO_RMS, RTL8169_RMS_MAX);
// enable ip/tcp/udp checksum offloading
// TODO: is this supported on all cards?
m_io_bar_region->write16(RTL8169_IO_CPlusCR, 1 << 5);
return {}; return {};
} }
@@ -257,31 +261,49 @@ namespace Kernel
for (;;) for (;;)
{ {
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[m_rx_head]; auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[m_rx_head];
const auto command = descriptor.command;
if (descriptor.command & RTL8169_DESC_CMD_OWN) if (descriptor.command & RTL8169_DESC_CMD_OWN)
break; break;
// packet buffer can only hold single packet, so we should not receive any multi-descriptor packets // packet buffer can only hold single packet, so we should not receive any multi-descriptor packets
ASSERT((descriptor.command & RTL8169_DESC_CMD_LS) && (descriptor.command & RTL8169_DESC_CMD_FS)); ASSERT((command & RTL8169_DESC_CMD_LS) && (command & RTL8169_DESC_CMD_FS));
const uint16_t packet_length = descriptor.command & 0x3FFF; const uint8_t protocol = (command >> 17) & 3;
const uint16_t packet_length = command & 0x3FFF;
if (packet_length > s_buffer_size) if (packet_length > s_buffer_size)
dwarnln("Got {} bytes to {} byte buffer", packet_length, s_buffer_size); dwarnln("Got {} bytes to {} byte buffer", packet_length, s_buffer_size);
else if (descriptor.command & (1u << 21)) else if (command & (1u << 21))
; // descriptor has an error dwarnln("descriptor error {4h}", command);
else if (protocol == 1 && (command & (1u << 14)))
dwarnln("TCP checksum error");
else if (protocol == 2 && (command & (1u << 15)))
dwarnln("UDP checksum error");
else if (protocol != 0 && (command & (1u << 16)))
dwarnln("IPv4 checksum error");
else else
{ {
m_rx_lock.unlock(InterruptState::Enabled); m_rx_lock.unlock(InterruptState::Enabled);
uint32_t validated_cksums;
switch (protocol)
{
case 0: validated_cksums = 0; break;
case 1: validated_cksums = CKSUM_IPV4 | CKSUM_TCP; break;
case 2: validated_cksums = CKSUM_IPV4 | CKSUM_UDP; break;
case 3: validated_cksums = CKSUM_IPV4; break;
}
const uint8_t* packet_data = reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + m_rx_head * s_buffer_size); const uint8_t* packet_data = reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + m_rx_head * s_buffer_size);
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { packet_data, packet_length }, 0); NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { packet_data, packet_length }, validated_cksums);
m_rx_lock.lock(); m_rx_lock.lock();
} }
uint32_t command = 0x1FF8 | RTL8169_DESC_CMD_OWN; uint32_t new_command = 0x1FF8 | RTL8169_DESC_CMD_OWN;
if (m_rx_head == m_rx_descriptor_count - 1) if (m_rx_head == m_rx_descriptor_count - 1)
command |= RTL8169_DESC_CMD_EOR; new_command |= RTL8169_DESC_CMD_EOR;
descriptor.command = command; descriptor.command = new_command;
m_rx_head = (m_rx_head + 1) % m_rx_descriptor_count; m_rx_head = (m_rx_head + 1) % m_rx_descriptor_count;
} }