Kernel: Support hardware checksum offload on RTL8169 receive
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user