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
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 {};
}
@@ -257,31 +261,49 @@ namespace Kernel
for (;;)
{
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)
break;
// 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)
dwarnln("Got {} bytes to {} byte buffer", packet_length, s_buffer_size);
else if (descriptor.command & (1u << 21))
; // descriptor has an error
else if (command & (1u << 21))
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
{
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);
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();
}
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)
command |= RTL8169_DESC_CMD_EOR;
descriptor.command = command;
new_command |= RTL8169_DESC_CMD_EOR;
descriptor.command = new_command;
m_rx_head = (m_rx_head + 1) % m_rx_descriptor_count;
}