Kernel: Support hardware checksum offload on E1000 receive
This commit is contained in:
@@ -29,6 +29,7 @@ namespace Kernel
|
|||||||
REG_TDLEN = 0x3808,
|
REG_TDLEN = 0x3808,
|
||||||
REG_TDH = 0x3810,
|
REG_TDH = 0x3810,
|
||||||
REG_TDT = 0x3818,
|
REG_TDT = 0x3818,
|
||||||
|
REG_RXCSUM = 0x5000,
|
||||||
REG_MTA = 0x5200,
|
REG_MTA = 0x5200,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -167,6 +168,15 @@ namespace Kernel
|
|||||||
RCTL_BSIZE_16384 = (0b01 << 16) | RCTL_BSEX,
|
RCTL_BSIZE_16384 = (0b01 << 16) | RCTL_BSEX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum E1000_RXCSUM : uint32_t
|
||||||
|
{
|
||||||
|
RXSUM_IPOFLD = 1 << 8,
|
||||||
|
RXSUM_TUOFLD = 1 << 9,
|
||||||
|
RXSUM_CRCOFLD = 1 << 11,
|
||||||
|
RXSUM_IPPCE = 1 << 12,
|
||||||
|
RXSUM_PCSD = 1 << 13,
|
||||||
|
};
|
||||||
|
|
||||||
enum E1000_CMD : uint8_t
|
enum E1000_CMD : uint8_t
|
||||||
{
|
{
|
||||||
CMD_EOP = 1 << 0,
|
CMD_EOP = 1 << 0,
|
||||||
@@ -178,6 +188,26 @@ namespace Kernel
|
|||||||
CMD_IDE = 1 << 7,
|
CMD_IDE = 1 << 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum E1000_RX_STS : uint8_t
|
||||||
|
{
|
||||||
|
RX_STS_IPCS = 1 << 6,
|
||||||
|
RX_STS_TCPCS = 1 << 5,
|
||||||
|
RX_STS_UDPCS = 1 << 5,
|
||||||
|
RX_STS_EOP = 1 << 1,
|
||||||
|
RX_STS_DD = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum E1000_RX_ERR : uint8_t
|
||||||
|
{
|
||||||
|
RX_ERR_RXE = 1 << 7,
|
||||||
|
RX_ERR_IPE = 1 << 6,
|
||||||
|
RX_ERR_TCPE = 1 << 5,
|
||||||
|
RX_ERR_CXE = 1 << 4,
|
||||||
|
RX_ERR_SEQ = 1 << 2,
|
||||||
|
RX_ERR_SE = 1 << 1,
|
||||||
|
RX_ERR_CE = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
struct e1000_rx_desc
|
struct e1000_rx_desc
|
||||||
{
|
{
|
||||||
uint64_t addr;
|
uint64_t addr;
|
||||||
|
|||||||
@@ -202,6 +202,8 @@ namespace Kernel
|
|||||||
rctrl |= RCTL_BSIZE_8192;
|
rctrl |= RCTL_BSIZE_8192;
|
||||||
write32(REG_RCTL, rctrl);
|
write32(REG_RCTL, rctrl);
|
||||||
|
|
||||||
|
write32(REG_RXCSUM, RXSUM_IPOFLD | RXSUM_TUOFLD);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,20 +332,44 @@ namespace Kernel
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
auto& descriptor = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr())[rx_current];
|
auto& descriptor = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr())[rx_current];
|
||||||
if (!(descriptor.status & 1))
|
|
||||||
|
const auto status = descriptor.status;
|
||||||
|
if (!(status & RX_STS_DD))
|
||||||
break;
|
break;
|
||||||
ASSERT(descriptor.length <= E1000_RX_BUFFER_SIZE);
|
|
||||||
|
|
||||||
dprintln_if(DEBUG_E1000, "got {} bytes", (uint16_t)descriptor.length);
|
|
||||||
|
|
||||||
|
const auto errors = descriptor.errors;
|
||||||
|
if (!(status & RX_STS_EOP))
|
||||||
|
dwarnln("multi descriptor packet??");
|
||||||
|
else if (errors & (RX_ERR_CE | RX_ERR_SE | RX_ERR_RXE))
|
||||||
|
dwarnln("descriptor error {2h}", errors);
|
||||||
|
else if ((status & RX_STS_IPCS) && (errors & RX_ERR_IPE))
|
||||||
|
dwarnln("IPv4 checksum error");
|
||||||
|
else if ((status & RX_STS_TCPCS) && (errors & RX_ERR_TCPE))
|
||||||
|
dwarnln("TCP checkum error");
|
||||||
|
else if ((status & RX_STS_UDPCS) && (errors & RX_ERR_TCPE))
|
||||||
|
dwarnln("UDP checksum error");
|
||||||
|
else
|
||||||
|
{
|
||||||
m_rx_lock.unlock(InterruptState::Enabled);
|
m_rx_lock.unlock(InterruptState::Enabled);
|
||||||
|
|
||||||
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
|
const uint32_t packet_length = descriptor.length;
|
||||||
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE),
|
ASSERT(packet_length <= E1000_RX_BUFFER_SIZE);
|
||||||
descriptor.length
|
|
||||||
}, 0);
|
dprintln_if(DEBUG_E1000, "got {} bytes", packet_length);
|
||||||
|
|
||||||
|
uint32_t validated_cksums = 0;
|
||||||
|
if ((status & RX_STS_IPCS) && !(errors & RX_ERR_IPE))
|
||||||
|
validated_cksums |= CKSUM_IPV4;
|
||||||
|
if ((status & RX_STS_TCPCS) && !(errors & RX_ERR_TCPE))
|
||||||
|
validated_cksums |= CKSUM_TCP;
|
||||||
|
if ((status & RX_STS_UDPCS) && !(errors & RX_ERR_TCPE))
|
||||||
|
validated_cksums |= CKSUM_UDP;
|
||||||
|
|
||||||
|
const uint8_t* packet_data = reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE);
|
||||||
|
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { packet_data, packet_length }, validated_cksums);
|
||||||
|
|
||||||
m_rx_lock.lock();
|
m_rx_lock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
descriptor.status = 0;
|
descriptor.status = 0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user