Skip to content

Commit

Permalink
dwc_eqos - jumbo packets up to 4088 (#35)
Browse files Browse the repository at this point in the history
Support jumbo packets up to 4088 bytes (MTU 4074). This means raising
the receive buffer size up to 4096, but since it appears that
NetAdapterCx allocates buffers at page granularity anyway, I don't think
this actually costs anything.

I tried to enable 9014-byte packets, but with system-managed buffering,
I can't see how to specify that I want a small buffer (e.g. 2KB or 4KB) while
also indicating that I might receive a large packet (e.g. 9014 bytes) -- the
two sizes appear to be tied together. I think if we want 9014-byte jumbo
frames, we either use 12KB receive buffers (very inefficient use of
memory) or we use driver-managed receive buffers (a bit more work that I
can't finish tonight). So stick with a 4088 byte limit for now.
  • Loading branch information
idigdoug authored Jan 8, 2024
1 parent 749f0e0 commit 4739f2d
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 12 deletions.
43 changes: 37 additions & 6 deletions drivers/net/dwc_eqos/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ static auto constexpr BusBytes = 8u;
static auto constexpr QueuesSupported = 1u; // TODO: Support multiple queues?
static auto constexpr InterruptLinkStatus = 0x80000000u;
static auto constexpr InterruptChannel0StatusMask = ~InterruptLinkStatus;
static UINT16 constexpr JumboPacketMin = 1514u;
static UINT16 constexpr JumboPacketMax = RxBufferSize - 8u; // 8 == VLAN + CRC. TODO: 9014-byte jumbo frames.

// D637828D-556C-4829-966A-237072F00FF1
static GUID constexpr DsmGuid = { 0xD637828D, 0x556C, 0x4829, 0x96, 0x6A, 0x23, 0x70, 0x72, 0xF0, 0x0F, 0xF1 };
Expand Down Expand Up @@ -637,17 +639,32 @@ DeviceD0Entry(
macConfig.TransmitterEnable = true;
macConfig.DisableCarrierSenseDuringTransmit = true;
macConfig.DisableReceiveOwn = true;
macConfig.JabberDisable = context->config.jumboFrame > 2000;
macConfig.PacketBurstEnable = true;
//macConfig.PadOrCrcStripEnable = true; // Why doesn't this work?
//macConfig.CrcStripEnableForType = true; // Why doesn't this work?
macConfig.GiantPacketSizeLimitControlEnable = context->config.jumboFrame > JumboPacketMin;
macConfig.ChecksumOffloadEnable = context->config.txCoeSel || context->config.rxCoeSel;
Write32(&context->regs->Mac_Configuration, macConfig);

Mac_Vlan_Tag_Ctrl_t vlanTagCtrl = {};
MacExtConfiguration_t macExtConfig = {};
macExtConfig.GiantPacketSizeLimit = context->config.jumboFrame + 4; // Includes CRC, excludes VLAN.
Write32(&context->regs->Mac_Ext_Configuration, macExtConfig);

MacVlanTagCtrl_t vlanTagCtrl = {};
vlanTagCtrl.StripOnReceive = VlanTagStripOnReceive_Always;
vlanTagCtrl.RxStatusEnable = true;
Write32(&context->regs->Mac_Vlan_Tag_Ctrl, vlanTagCtrl);

MacWatchdogTimeout_t watchdogTimeout = {};
// 0 = 2KB, 1 = 3KB, ... 14 = 16KB, 15 = Reserved.
// jumboFrame value doesn't include VLAN or CRC, so add 8.
// We want to round up a 1KB boundary, so add 1023.
// Example: If jumboFrame is 2040 then WatchdogTimeout = 0, but if jumboFrame is 2041 then WatchdogTimeout = 1.
watchdogTimeout.WatchdogTimeout = static_cast<UINT8>((context->config.jumboFrame + 8 + 1023) / 1024 - 2);
watchdogTimeout.ProgrammableWatchdogEnable = context->config.jumboFrame > 2000;
Write32(&context->regs->Mac_Watchdog_Timeout, watchdogTimeout);

// Clear any pending interrupts, then unmask them.

NT_ASSERT(ReadNoFence8(&context->updateLinkStateBusy) == 0);
Expand Down Expand Up @@ -715,6 +732,7 @@ DevicePrepareHardware(
auto const context = DeviceGetContext(device);
bool configHasMacAddress = false;
ULONG flowControlConfiguration;
ULONG jumboPacketConfiguration;

// Read configuration

Expand Down Expand Up @@ -755,14 +773,23 @@ DevicePrepareHardware(
configHasMacAddress = true;
}

DECLARE_CONST_UNICODE_STRING(FlowControl_Name, L"FlowControl");
DECLARE_CONST_UNICODE_STRING(FlowControl_Name, L"*FlowControl");
status = NetConfigurationQueryUlong(configuration, NET_CONFIGURATION_QUERY_ULONG_NO_FLAGS, &FlowControl_Name, &flowControlConfiguration);
if (!NT_SUCCESS(status))
{
TraceWrite("QueryFlowControl-not-found", LEVEL_VERBOSE,
TraceLoggingNTStatus(status));
flowControlConfiguration = 3; // Default = TxRxEnabled
}

DECLARE_CONST_UNICODE_STRING(JumboPacket_Name, L"*JumboPacket");
status = NetConfigurationQueryUlong(configuration, NET_CONFIGURATION_QUERY_ULONG_NO_FLAGS, &JumboPacket_Name, &jumboPacketConfiguration);
if (!NT_SUCCESS(status))
{
TraceWrite("QueryJumboPacket-not-found", LEVEL_VERBOSE,
TraceLoggingNTStatus(status));
jumboPacketConfiguration = JumboPacketMin;
}
}

// Configure resources
Expand Down Expand Up @@ -949,6 +976,10 @@ DevicePrepareHardware(
context->config.wr_osr_lmt = 4;
context->config.rd_osr_lmt = 8;
context->config.blen = 0x7; // 0x7 = 4, 8, 16
context->config.jumboFrame = static_cast<UINT16>(
jumboPacketConfiguration < JumboPacketMin ? JumboPacketMin
: jumboPacketConfiguration > JumboPacketMax ? JumboPacketMax
: jumboPacketConfiguration);

switch (flowControlConfiguration)
{
Expand Down Expand Up @@ -1132,7 +1163,7 @@ DevicePrepareHardware(
? WdfDmaProfileScatterGather
: WdfDmaProfileScatterGather64;
WDF_DMA_ENABLER_CONFIG config;
WDF_DMA_ENABLER_CONFIG_INIT(&config, profile, 16384); // TODO: Jumbo packets.
WDF_DMA_ENABLER_CONFIG_INIT(&config, profile, 16384);
config.WdmDmaVersionOverride = 3;

switch (context->feature1.AddressWidth)
Expand Down Expand Up @@ -1183,7 +1214,7 @@ DevicePrepareHardware(
NET_ADAPTER_LINK_LAYER_CAPABILITIES_INIT(&linkCaps, maxSpeed, maxSpeed);
NetAdapterSetLinkLayerCapabilities(context->adapter, &linkCaps);

NetAdapterSetLinkLayerMtuSize(context->adapter, 1500); // TODO: Jumbo packets.
NetAdapterSetLinkLayerMtuSize(context->adapter, context->config.jumboFrame - 14);

NET_ADAPTER_DMA_CAPABILITIES dmaCaps;
NET_ADAPTER_DMA_CAPABILITIES_INIT(&dmaCaps, context->dma);
Expand All @@ -1193,8 +1224,8 @@ DevicePrepareHardware(
NET_ADAPTER_TX_CAPABILITIES_INIT_FOR_DMA(&txCaps, &dmaCaps, QueuesSupported);
txCaps.MaximumNumberOfFragments = QueueDescriptorMinCount - 2; // = 1 hole in the ring + 1 context descriptor.

NET_ADAPTER_RX_CAPABILITIES rxCaps; // TODO: Might use less memory if driver-managed.
NET_ADAPTER_RX_CAPABILITIES_INIT_SYSTEM_MANAGED_DMA(&rxCaps, &dmaCaps, RxBufferSize, QueuesSupported); // TODO: Jumbo packets.
NET_ADAPTER_RX_CAPABILITIES rxCaps; // TODO: 9014-byte jumbo frames probably require custom buffering.
NET_ADAPTER_RX_CAPABILITIES_INIT_SYSTEM_MANAGED_DMA(&rxCaps, &dmaCaps, RxBufferSize, QueuesSupported);

NetAdapterSetDataPathCapabilities(context->adapter, &txCaps, &rxCaps);

Expand Down
1 change: 1 addition & 0 deletions drivers/net/dwc_eqos/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct DeviceConfig
UINT8 blen : 7; // AXIC\snps,blen bitmask of 7 booleans 4..256 (default = 4, 8, 16).
bool txFlowControl; // Adapter configuration (Ndi\params\*FlowControl).
bool rxFlowControl; // Adapter configuration (Ndi\params\*FlowControl).
UINT16 jumboFrame; // Adapter configuration (Ndi\params\*JumboFrame). 1514..4088
};

// Referenced in driver.cpp DriverEntry.
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dwc_eqos/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

/*
Possible areas for improvement:
- Jumbo frames.
- 9014-byte jumbo frames (current limit is 4088).
This probably requires custom receive buffer management.
- Tx segmentation offload.
- Run against network test suites and fix any issues.
- Power control, wake-on-LAN, ARP offload.
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/dwc_eqos/dwc_eqos.inf
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ HKR, Ndi\params\NetworkAddress, LimitText, 0, "12"
HKR, Ndi\params\NetworkAddress, UpperCase, 0, "1"
HKR, Ndi\params\NetworkAddress, Optional, 0, "1"

HKR, Ndi\params\*JumboPacket, ParamDesc, 0, %JumboPacket%
HKR, Ndi\params\*JumboPacket, type, 0, "int"
HKR, Ndi\params\*JumboPacket, default, 0, "1514"
HKR, Ndi\params\*JumboPacket, min, 0, "1514"
HKR, Ndi\params\*JumboPacket, max, 0, "4088" ; TODO: 9014-byte jumbo frames.

HKR, Ndi\params\*FlowControl, ParamDesc, 0, %FlowControl%
HKR, Ndi\params\*FlowControl, default, 0, "3"
HKR, Ndi\params\*FlowControl, type, 0, "enum"
Expand Down Expand Up @@ -149,6 +155,7 @@ RKCP = "Rockchip"
DWCEQOS.DeviceDesc = "Synopsys DesignWare Ethernet Quality of Service (GMAC)"
DWCEQOS.ServiceDesc = "DesignWare Ethernet"
NetworkAddress = "Network Address"
JumboPacket = "Jumbo Packet"
FlowControl = "Flow Control"
PriorityVlanTag = "Packet Priority & VLAN"
TCPUDPChecksumOffloadIPv4 = "TCP/UDP Checksum Offload (IPv4)"
Expand Down
20 changes: 17 additions & 3 deletions drivers/net/dwc_eqos/registers.h
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ enum VlanTagStripOnReceive : UINT8
VlanTagStripOnReceive_Always,
};

union Mac_Vlan_Tag_Ctrl_t
union MacVlanTagCtrl_t
{
UINT32 Value32;
struct
Expand Down Expand Up @@ -930,6 +930,20 @@ union MacTxFlowCtrl_t
};
};

union MacWatchdogTimeout_t
{
UINT32 Value32;
struct
{
UINT8 WatchdogTimeout; // WTO; effective timeout is (WatchdogTimeout * 1024) + 2048 bytes.

UINT8 ProgrammableWatchdogEnable : 1; // PWE
UINT8 Reserved9 : 7;
UINT8 Reserved16 : 8;
UINT8 Reserved24 : 8;
};
};

struct MacRegisters
{
// MAC_Configuration @ 0x0000 = 0x0:
Expand All @@ -949,7 +963,7 @@ struct MacRegisters
// MAC_Watchdog_Timeout @ 0x000C = 0x0:
// The Watchdog Timeout register controls the watchdog timeout for received
// packets.
ULONG Mac_Watchdog_Timeout;
MacWatchdogTimeout_t Mac_Watchdog_Timeout;

// MAC_Hash_Table_RegX @ 0x0010 = 0x0:
// The Hash Table Register X contains the Xth 32 bits of the hash table.
Expand All @@ -961,7 +975,7 @@ struct MacRegisters
// This register is the redefined format of the MAC VLAN Tag Register. It is used
// for indirect addressing. It contains the address offset, command type and Busy
// Bit for CSR access of the Per VLAN Tag registers.
Mac_Vlan_Tag_Ctrl_t Mac_Vlan_Tag_Ctrl;
MacVlanTagCtrl_t Mac_Vlan_Tag_Ctrl;

// MAC_VLAN_Tag_Data @ 0x0054 = 0x0:
// This register holds the read/write data for Indirect Access of the Per VLAN Tag
Expand Down
1 change: 0 additions & 1 deletion drivers/net/dwc_eqos/rxqueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ RxQueueAdvance(_In_ NETPACKETQUEUE queue)
auto const descWrite = desc.Write;

// Descriptor is still owned by the DMA engine?
NT_ASSERT(!descWrite.Own);
if (descWrite.Own)
{
/*
Expand Down
6 changes: 5 additions & 1 deletion drivers/net/dwc_eqos/rxqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ Receive queue behavior. Similar to the transmit queue.
struct DeviceContext;
struct DeviceConfig;
struct ChannelRegisters;
auto constexpr RxBufferSize = 2048u;

// NetAdapterCx appears to allocate fragment buffers in multiples of PAGE_SIZE,
// so there's no reason to use a size smaller than this. 4KB buffers allow us
// to receive jumbo packets up to 4088 bytes.
auto constexpr RxBufferSize = 4096u;

// Called by device.cpp AdapterCreateRxQueue.
_IRQL_requires_same_
Expand Down

0 comments on commit 4739f2d

Please sign in to comment.