diff --git a/drivers/net/dwc_eqos/descriptors.h b/drivers/net/dwc_eqos/descriptors.h
new file mode 100644
index 0000000..d8776dc
--- /dev/null
+++ b/drivers/net/dwc_eqos/descriptors.h
@@ -0,0 +1,328 @@
+/*
+Descriptor layout for the DesignWare EQOS Ethernet controller.
+*/
+#pragma once
+
+#define DESCRIPTOR_ALIGN 64u
+
+#if DBG
+#define TX_DESCRIPTOR_DBG_SIZE 24u
+#define RX_DESCRIPTOR_DBG_SIZE 20u
+#else // DBG
+#define TX_DESCRIPTOR_DBG_SIZE 16u
+#define RX_DESCRIPTOR_DBG_SIZE 16u
+#endif // DBG
+
+enum TxChecksumInsertion : UINT16
+{
+ TxChecksumInsertionDisabled = 0,
+ TxChecksumInsertionEnabledHeaderOnly = 1,
+ TxChecksumInsertionEnabledExceptPseudo = 2,
+ TxChecksumInsertionEnabledIncludingPseudo = 3,
+};
+
+struct TxDescriptorRead
+{
+ // TDES0, TDES1
+
+ UINT32 Buf1Ap; // BUF1AP
+ UINT32 Buf2Ap; // BUF2AP
+
+ // TDES2
+
+ UINT16 Buf1Length : 14; // B1L
+ UINT16 VlanTagControl : 2; // VTIR
+
+ UINT16 Buf2Length : 14; // B2L
+ UINT16 TransmitTimestampEnable : 1; // TTSE
+ UINT16 InterruptOnCompletion : 1; // IOC
+
+ // TDES3
+
+ UINT16 FrameLength; // FL (15 bits)
+
+ TxChecksumInsertion ChecksumInsertion : 2; // CIC
+ UINT16 TcpSegmentationEnable : 1; // TSE = 0
+ UINT16 SlotNumber : 4; // Slot Number Control Bits in AV Mode
+ UINT16 SourceAddressInsertionControl : 3; // SAIC
+ UINT16 CrcPadControl : 2; // CPC
+ UINT16 LastDescriptor : 1; // LD
+ UINT16 FirstDescriptor : 1; // FD
+ UINT16 ContextType : 1; // CTXT = 0
+ UINT16 Own : 1; // OWN
+
+#if DBG
+ UINT32 FragmentIndex;
+ UINT32 PacketIndex;
+#endif
+};
+static_assert(sizeof(TxDescriptorRead) == TX_DESCRIPTOR_DBG_SIZE);
+
+struct TxDescriptorReadTso
+{
+ // TDES0, TDES1
+
+ UINT32 Buf1Ap; // BUF1AP, TSO Header Address Pointer if FD = 1
+ UINT32 Buf2Ap; // BUF2AP
+
+ // TDES2
+
+ UINT16 Buf1Length : 14; // B1L (10-bit header length if FD = 1)
+ UINT16 VlanTagControl : 2; // VTIR
+
+ UINT16 Buf2Length : 14; // B2L
+ UINT16 TsoMemoryWriteDisable : 1; // TMWD
+ UINT16 InterruptOnCompletion : 1; // IOC
+
+ // TDES3
+
+ UINT32 TcpPayloadLength : 18; // TPL
+ UINT32 TcpSegmentationEnable : 1; // TSE = 0
+ UINT32 TcpHeaderLength : 4; // TCP/UDP header length (must be 2 for UDP)
+ UINT32 SourceAddressInsertionControl : 3; // SAIC
+ UINT32 Reserved26 : 2; // CPC, ignored when TSE = 1
+ UINT32 LastDescriptor : 1; // LD
+ UINT32 FirstDescriptor : 1; // FD
+ UINT32 ContextType : 1; // CTXT = 0
+ UINT32 Own : 1; // OWN
+
+#if DBG
+ UINT32 FragmentIndex;
+ UINT32 PacketIndex;
+#endif
+};
+static_assert(sizeof(TxDescriptorReadTso) == TX_DESCRIPTOR_DBG_SIZE);
+
+struct TxDescriptorWrite
+{
+ // TDES0, TDES1
+
+ UINT32 TimestampLow; // TTSL
+ UINT32 TimestampHigh; // TTSH
+
+ // TDES2
+
+ UINT32 Reserved;
+
+ // TDES3
+
+ UINT8 IpHeaderError : 1; // IHE
+ UINT8 DeferredBit : 1; // DB
+ UINT8 UnderflowError : 1; // UF
+ UINT8 ExcessiveDeferral : 1; // ED
+ UINT8 CollisionCount : 4; // CC
+
+ UINT8 ExcessiveCollision : 1; // EC
+ UINT8 LateCollision : 1; // LC
+ UINT8 NoCarrier : 1; // NC
+ UINT8 LossOfCarrier : 1; // LC
+ UINT8 PayloadChecksumError : 1; // PCE
+ UINT8 PacketFlushed : 1; // PF
+ UINT8 JabberTimeout : 1; // JT
+ UINT8 ErrorSummary : 1; // ES
+
+ UINT8 EccUncorrectableError : 1; // EUE
+ UINT8 TimestampStatus : 1; // TTSS
+ UINT8 Reserved18 : 5;
+ UINT8 DescriptorError : 1; // DE
+
+ UINT8 Reserved24 : 4;
+ UINT8 LastDescriptor : 1; // LD
+ UINT8 FirstDescriptor : 1; // FD
+ UINT8 ContextType : 1; // CTXT = 0
+ UINT8 Own : 1; // OWN
+
+#if DBG
+ UINT32 FragmentIndex;
+ UINT32 PacketIndex;
+#endif
+};
+static_assert(sizeof(TxDescriptorWrite) == TX_DESCRIPTOR_DBG_SIZE);
+
+struct TxDescriptorContext
+{
+ // TDES0, TDES1
+
+ UINT32 TimestampLow; // TTSL
+ UINT32 TimestampHigh; // TTSH
+
+ // TDES2
+
+ UINT16 MaximumSegmentSize : 14; // MSS
+ UINT16 Reserved14 : 2;
+
+ UINT16 InnerVlanTag; // IVT
+
+ // TDES3
+
+ UINT16 VlanTag; // VT
+
+ UINT8 VlanTagValid : 1; // VLTV
+ UINT8 InnerVlanTagValid : 1; // IVLTV
+ UINT8 InnverVlanTagControl : 2; // IVTIR
+ UINT8 Reserved20 : 3;
+ UINT8 DescriptorError : 1; // DE
+
+ UINT8 Reserved24 : 2;
+ UINT8 OneStepInputOrMssValid : 1; // TCMSSV
+ UINT8 OneStepEnable : 1; // OSTC
+ UINT8 Reserved28 : 2;
+ UINT8 ContextType : 1; // CTXT = 1
+
+#if DBG
+ UINT32 FragmentIndex;
+ UINT32 PacketIndex;
+#endif
+};
+static_assert(sizeof(TxDescriptorContext) == TX_DESCRIPTOR_DBG_SIZE);
+
+struct RxDescriptorRead
+{
+ // RDES0, RDES1
+
+ UINT32 Buf1ApLow; // BUF1AP
+ UINT32 Buf1ApHigh; // BUF1AP
+
+ // RDES2
+
+ UINT32 Buf2Ap; // BUF2AP
+
+ // RDES3
+
+ UINT16 Reserved0;
+ UINT8 Reserved16;
+
+ UINT8 Buf1Valid : 1; // BUF1V
+ UINT8 Buf2Valid : 1; // BUF2V
+ UINT8 Reserved26 : 4;
+ UINT8 InterruptOnCompletion : 1; // IOC
+ UINT8 Own : 1; // OWN
+
+#if DBG
+ UINT32 FragmentIndex;
+#endif
+};
+static_assert(sizeof(RxDescriptorRead) == RX_DESCRIPTOR_DBG_SIZE);
+
+enum RxPayloadType : UINT8
+{
+ RxPayloadTypeUnknown = 0,
+ RxPayloadTypeUdp,
+ RxPayloadTypeTcp,
+ RxPayloadTypeIcmp,
+ RxPayloadTypeIgmp,
+ RxPayloadTypeAvUntaggedControl,
+ RxPayloadTypeAvTaggedData,
+ RxPayloadTypeAvTaggedControl,
+};
+
+struct RxDescriptorWrite
+{
+ // RDES0
+
+ UINT16 OuterVlanTag; // OVT
+ UINT16 InnerVlanTag; // IVT
+
+ // RDES1
+
+ RxPayloadType PayloadType : 3; // PT
+ UINT8 IPHeaderError : 1; // IPHE
+ UINT8 IPv4HeaderPresent : 1; // IPV4
+ UINT8 IPv6HeaderPresent : 1; // IPV6
+ UINT8 IPChecksumBypassed : 1; // IPCB
+ UINT8 IPPayloadError : 1; // IPCE
+
+ UINT8 PtpMessageType : 4; // PMT
+ UINT8 PtpPacketType : 1; // PFT
+ UINT8 PtpVersion : 1; // PV
+ UINT8 TimestampAvailable : 1; // TSA
+ UINT8 TimestampDropped : 1; // TD
+
+ UINT16 OamSubtype; // OPC - OAM sub-type and code, or MAC control packet opcode (based on LengthType).
+
+ // RDES2
+
+ UINT16 L3L4HeaderLength : 10; // HL
+ UINT16 ArpReplyNotGenerated : 1; // ARPNR
+ UINT16 Reserved11 : 3;
+ UINT16 InnerVlanTagStatus : 1; // ITS
+ UINT16 VlanFilterStatus : 1; // OTS
+
+ UINT16 SourceFilterFail : 1; // SAF/RXPD, based on Flexible RX Parser enable.
+ UINT16 DestinationFilterFail : 1; // DAF/RXPI, based on Flexible RX Parser enable.
+ UINT16 HashFilterStatus : 1; // HF
+ UINT16 MacAddressMatchHashValue : 8; // MADRM
+ UINT16 L3FilterMatch : 1; // L3FM
+ UINT16 L4FilterMatch : 1; // L4FM
+ UINT16 L3L4FilterNumber : 3; // L3L4FM
+
+ // RDES3
+
+ UINT16 PacketLength : 15; // PL
+ UINT16 ErrorSummary : 1; // ES
+
+ UINT8 LengthType : 3; // LT
+ UINT8 DribbleBitError : 1; // DE
+ UINT8 ReceiveError : 1; // RE
+ UINT8 OverflowError : 1; // OE
+ UINT8 ReceiveWatchdogTimeout : 1; // RWT
+ UINT8 GiantPacket : 1; // GP
+
+ UINT8 CrcError : 1; // CE
+ UINT8 Rdes0Valid : 1; // RS0V, valid only if LD = 1.
+ UINT8 Rdes1Valid : 1; // RS1V, valid only if LD = 1.
+ UINT8 Rdes2Valid : 1; // RS2V, valid only if LD = 1.
+ UINT8 LastDescriptor : 1; // LD
+ UINT8 FirstDescriptor : 1; // FD
+ UINT8 ContextType : 1; // CTXT = 0
+ UINT8 Own : 1; // OWN
+
+#if DBG
+ UINT32 FragmentIndex;
+#endif
+};
+static_assert(sizeof(RxDescriptorWrite) == RX_DESCRIPTOR_DBG_SIZE);
+
+struct RxDescriptorContext
+{
+ UINT32 TimestampLow; // RSTL
+ UINT32 TimestampHigh; // RSTH
+ UINT32 Reserved2;
+
+ // RDES3
+
+ UINT16 Reserved3a;
+ UINT8 Reserved3b;
+ UINT8 Reserved3c : 5;
+ UINT8 DescriptorError : 1; // DE
+ UINT8 ContextType : 1; // CTXT = 0
+ UINT8 Own : 1; // OWN
+
+#if DBG
+ UINT32 FragmentIndex;
+#endif
+};
+static_assert(sizeof(RxDescriptorContext) == RX_DESCRIPTOR_DBG_SIZE);
+
+union TxDescriptor
+{
+ TxDescriptorRead Read; // When read, TSE = 0, CTXT = 0.
+ TxDescriptorReadTso ReadTso;// When read, TSE = 1, CTXT = 0.
+ TxDescriptorWrite Write; // When write, CTXT = 0.
+ TxDescriptorContext Context;// When CTXT = 1.
+ UINT32 All[DESCRIPTOR_ALIGN / sizeof(UINT32)];
+};
+static_assert(sizeof(TxDescriptor) == DESCRIPTOR_ALIGN);
+
+union RxDescriptor
+{
+ RxDescriptorRead Read; // When read.
+ RxDescriptorWrite Write; // When write, CTXT = 0.
+ RxDescriptorContext Context;// When write, CTXT = 1.
+ UINT32 All[DESCRIPTOR_ALIGN / sizeof(UINT32)];
+};
+static_assert(sizeof(RxDescriptor) == DESCRIPTOR_ALIGN);
+
+#undef DESCRIPTOR_ALIGN
+#undef TX_DESCRIPTOR_DBG_SIZE
+#undef RX_DESCRIPTOR_DBG_SIZE
diff --git a/drivers/net/dwc_eqos/device.cpp b/drivers/net/dwc_eqos/device.cpp
index f590775..cf9f40c 100644
--- a/drivers/net/dwc_eqos/device.cpp
+++ b/drivers/net/dwc_eqos/device.cpp
@@ -29,7 +29,7 @@ static auto constexpr DefaultCsrRate = 125'000'000u;
static auto constexpr BusBytes = 8u;
static auto constexpr QueuesSupported = 1u; // TODO: Support multiple queues?
static auto constexpr InterruptLinkStatus = 0x80000000u;
-static auto constexpr InterruptChannel0Status = ~InterruptLinkStatus;
+static auto constexpr InterruptChannel0StatusMask = ~InterruptLinkStatus;
// D637828D-556C-4829-966A-237072F00FF1
static GUID constexpr DsmGuid = { 0xD637828D, 0x556C, 0x4829, 0x96, 0x6A, 0x23, 0x70, 0x72, 0xF0, 0x0F, 0xF1 };
@@ -105,24 +105,22 @@ static void
SetOneMacAddress(_Inout_ MacRegisters* regs, unsigned index, _In_reads_(6) UINT8 const* addr, bool enable)
{
// PASSIVE_LEVEL, nonpaged (resume path)
- MacAddressLow_t regLo = {};
- regLo.Addr0 = addr[0];
- regLo.Addr1 = addr[1];
- regLo.Addr2 = addr[2];
- regLo.Addr3 = addr[3];
-
- MacAddressHigh_t regHi = {};
- regHi.Addr4 = addr[4];
- regHi.Addr5 = addr[5];
- regHi.AddressEnable = enable;
-
- Write32(®s->Mac_Address[index].High, regHi);
- Write32(®s->Mac_Address[index].Low, regLo);
+ MacAddressRegisters addrRegs = {};
+ addrRegs.Low.Addr0 = addr[0];
+ addrRegs.Low.Addr1 = addr[1];
+ addrRegs.Low.Addr2 = addr[2];
+ addrRegs.Low.Addr3 = addr[3];
+ addrRegs.High.Addr4 = addr[4];
+ addrRegs.High.Addr5 = addr[5];
+ addrRegs.High.AddressEnable = enable;
+
+ Write32(®s->Mac_Address[index].High, addrRegs.High);
+ Write32(®s->Mac_Address[index].Low, addrRegs.Low);
TraceEntryExit(SetOneMacAddress, LEVEL_VERBOSE,
TraceLoggingUInt32(index),
- TraceLoggingHexInt32(regHi.Value32, "MacHi"),
- TraceLoggingHexInt32(regLo.Value32, "MacLo"));
+ TraceLoggingHexInt32(addrRegs.High.Value32, "MacHi"),
+ TraceLoggingHexInt32(addrRegs.Low.Value32, "MacLo"));
}
// Perform a software reset, then set mac address 0 to the specified value.
@@ -337,7 +335,7 @@ DeviceInterruptIsr(
}
auto const channel0 = Read32(®s->Dma_Ch[0].Status);
- newInterruptStatus.Value32 |= channel0.Value32 & InterruptChannel0Status;
+ newInterruptStatus.Value32 |= channel0.Value32 & InterruptChannel0StatusMask;
if (newInterruptStatus.Value32 != 0)
{
@@ -523,7 +521,7 @@ AdapterSetReceiveFilter(
SetOneMacAddress(context->regs, 0, context->currentMacAddress,
0 != (flags & NetPacketFilterFlagDirected)); // Address[0] can't really be disabled...
- // Could also use hash-based filtering for additional mcast support, but this seems okay.
+ // Could use hash-based filtering for additional mcast support, but this seems okay.
auto const macAddrCount = context->feature0.MacAddrCount;
for (unsigned i = 1; i < macAddrCount; i += 1)
{
@@ -1212,12 +1210,10 @@ DevicePrepareHardware(
Write32(®s->Mac_1us_Tic_Counter, DefaultCsrRate / 1'000'000u - 1);
- static_assert(sizeof(RxDescriptor) == sizeof(TxDescriptor),
- "RxDescriptor must be same size as TxDescriptor.");
- static_assert(sizeof(RxDescriptor) % BusBytes == 0,
- "RxDescriptor must be a multiple of bus width.");
+ static_assert(QueueDescriptorSize % BusBytes == 0,
+ "QueueDescriptorSize must be a multiple of bus width.");
ChannelDmaControl_t dmaControl = {};
- dmaControl.DescriptorSkipLength = (sizeof(RxDescriptor) - 16) / BusBytes;
+ dmaControl.DescriptorSkipLength = (QueueDescriptorSize - 16) / BusBytes;
dmaControl.PblX8 = context->config.pblX8;
Write32(®s->Dma_Ch[0].Control, dmaControl);
diff --git a/drivers/net/dwc_eqos/device.h b/drivers/net/dwc_eqos/device.h
index f6dab5b..298da46 100644
--- a/drivers/net/dwc_eqos/device.h
+++ b/drivers/net/dwc_eqos/device.h
@@ -3,7 +3,7 @@ Device behavior. Includes adapter and interrupt since they are 1:1 with the devi
*/
#pragma once
-struct DeviceContext; // Multi-queue: change to DeviceQueueContext.
+struct DeviceContext; // TODO: if we do multi-queue, make a DeviceQueueContext struct instead.
// Information about the device provided to the queues.
struct DeviceConfig
@@ -11,7 +11,7 @@ struct DeviceConfig
bool txCoeSel; // MAC_HW_Feature0\TXCOESEL (hardware support for tx checksum offload).
bool rxCoeSel; // MAC_HW_Feature0\RXCOESEL (hardware support for rx checksum offload).
bool pblX8; // _DSD\snps,pblx8 (default = 1).
- UINT8 pbl; // _DSD\snps,pbl (default = 8).
+ UINT8 pbl; // _DSD\snps,pbl (default = 8; effect depends on pblX8).
UINT8 txPbl; // _DSD\snps,txpbl (default = pbl; effect depends on pblX8).
UINT8 rxPbl; // _DSD\snps,rxpbl (default = pbl; effect depends on pblX8).
bool fixed_burst; // _DSD\snps,fixed-burst (default = 0).
diff --git a/drivers/net/dwc_eqos/driver.cpp b/drivers/net/dwc_eqos/driver.cpp
index da7b1d5..379c529 100644
--- a/drivers/net/dwc_eqos/driver.cpp
+++ b/drivers/net/dwc_eqos/driver.cpp
@@ -5,11 +5,9 @@
/*
Possible areas for improvement:
- Run against network test suites and fix any issues.
-- Interrupt moderation and/or other CPU usage improvements.
- Jumbo frames.
- Configuration in registry (e.g. flow control, speed, duplex).
- Tx segmentation offload.
-- Rx segmentation offload.
- Wake-on-LAN.
- ARP offload.
- Multi-queue support?
@@ -18,7 +16,7 @@ Possible areas for improvement:
TRACELOGGING_DEFINE_PROVIDER(
TraceProvider,
"dwc_eqos",
- // *dwc_eqos = {5d8331d3-70b3-5620-5664-db28f48a4b79}
+ // {5d8331d3-70b3-5620-5664-db28f48a4b79} = Hash("dwc_eqos")
(0x5d8331d3, 0x70b3, 0x5620, 0x56, 0x64, 0xdb, 0x28, 0xf4, 0x8a, 0x4b, 0x79));
static EVT_WDF_DRIVER_UNLOAD DriverUnload;
diff --git a/drivers/net/dwc_eqos/dwc_eqos.vcxproj b/drivers/net/dwc_eqos/dwc_eqos.vcxproj
index 038c4e4..e546bd7 100644
--- a/drivers/net/dwc_eqos/dwc_eqos.vcxproj
+++ b/drivers/net/dwc_eqos/dwc_eqos.vcxproj
@@ -24,6 +24,7 @@
+
diff --git a/drivers/net/dwc_eqos/dwc_eqos.vcxproj.filters b/drivers/net/dwc_eqos/dwc_eqos.vcxproj.filters
index ee9bd58..0ca2068 100644
--- a/drivers/net/dwc_eqos/dwc_eqos.vcxproj.filters
+++ b/drivers/net/dwc_eqos/dwc_eqos.vcxproj.filters
@@ -47,6 +47,9 @@
Header Files
+
+ Header Files
+
diff --git a/drivers/net/dwc_eqos/queue_common.h b/drivers/net/dwc_eqos/queue_common.h
index 43963e4..6906e04 100644
--- a/drivers/net/dwc_eqos/queue_common.h
+++ b/drivers/net/dwc_eqos/queue_common.h
@@ -4,12 +4,12 @@ Definitions shared between TxQueue and RxQueue.
#pragma once
UINT32 constexpr QueueDescriptorSize = 64; // 64 == sizeof(TxDescriptor) == sizeof(RxDescriptor)
-UINT32 constexpr QueueDescriptorMinCount = PAGE_SIZE / QueueDescriptorSize;
-UINT32 constexpr QueueDescriptorMaxCount = 0x400;
+UINT32 constexpr QueueDescriptorMinCount = PAGE_SIZE / QueueDescriptorSize; // Page granularity for allocation, might as well use the whole page.
+UINT32 constexpr QueueDescriptorMaxCount = 0x400; // Hardware limitation.
-// Alignment is mainly to make sure the allocation does not cross a 4GB boundary,
-// but it also simplifies the QueueDescriptorAddressToIndex implementation.
-auto const QueueDescriptorAlignment = QueueDescriptorMaxCount * QueueDescriptorSize;
+// Alignment is primarily to make sure the allocation does not cross a 4GB boundary.
+// It also simplifies the QueueDescriptorAddressToIndex implementation.
+UINT32 constexpr QueueDescriptorAlignment = QueueDescriptorMaxCount * QueueDescriptorSize;
// Given the size of the fragment ring, return the number of descriptors to
// allocate for the descriptor ring. This will be a power of 2 between
diff --git a/drivers/net/dwc_eqos/registers.h b/drivers/net/dwc_eqos/registers.h
index 75bda53..17323da 100644
--- a/drivers/net/dwc_eqos/registers.h
+++ b/drivers/net/dwc_eqos/registers.h
@@ -1,5 +1,5 @@
/*
-Register and descriptor layout for the DesignWare EQOS Ethernet controller.
+Register layout for the DesignWare EQOS Ethernet controller.
*/
#pragma once
@@ -8,7 +8,7 @@ Register and descriptor layout for the DesignWare EQOS Ethernet controller.
#pragma region Read32/Write32
-// Prevents unwanted template type deduction.
+// Prevents unwanted template type deduction in Write32.
template
struct TypeIdentity { using type = T; };
@@ -1721,328 +1721,4 @@ static_assert(sizeof(MacRegisters) == 0x1200);
#pragma endregion
-#pragma region DmaDescriptor
-
-constexpr unsigned DESCRIPTOR_ALIGN = 64u;
-
-#if DBG
-#define TX_DESCRIPTOR_SIZE 24
-#define RX_DESCRIPTOR_SIZE 20
-#else
-#define TX_DESCRIPTOR_SIZE 16
-#define RX_DESCRIPTOR_SIZE 16
-#endif
-
-enum TxChecksumInsertion : UINT16
-{
- TxChecksumInsertionDisabled = 0,
- TxChecksumInsertionEnabledHeaderOnly = 1,
- TxChecksumInsertionEnabledExceptPseudo = 2,
- TxChecksumInsertionEnabledIncludingPseudo = 3,
-};
-
-struct TxDescriptorRead
-{
- // TDES0, TDES1
-
- UINT32 Buf1Ap; // BUF1AP
- UINT32 Buf2Ap; // BUF2AP
-
- // TDES2
-
- UINT16 Buf1Length : 14; // B1L
- UINT16 VlanTagControl : 2; // VTIR
-
- UINT16 Buf2Length : 14; // B2L
- UINT16 TransmitTimestampEnable : 1; // TTSE
- UINT16 InterruptOnCompletion : 1; // IOC
-
- // TDES3
-
- UINT16 FrameLength; // FL (15 bits)
-
- TxChecksumInsertion ChecksumInsertion : 2; // CIC
- UINT16 TcpSegmentationEnable : 1; // TSE = 0
- UINT16 SlotNumber : 4; // Slot Number Control Bits in AV Mode
- UINT16 SourceAddressInsertionControl : 3; // SAIC
- UINT16 CrcPadControl : 2; // CPC
- UINT16 LastDescriptor : 1; // LD
- UINT16 FirstDescriptor : 1; // FD
- UINT16 ContextType : 1; // CTXT = 0
- UINT16 Own : 1; // OWN
-
-#if DBG
- UINT32 FragmentIndex;
- UINT32 PacketIndex;
-#endif
-};
-static_assert(sizeof(TxDescriptorRead) == TX_DESCRIPTOR_SIZE);
-
-struct TxDescriptorReadTso
-{
- // TDES0, TDES1
-
- UINT32 Buf1Ap; // BUF1AP, TSO Header Address Pointer if FD = 1
- UINT32 Buf2Ap; // BUF2AP
-
- // TDES2
-
- UINT16 Buf1Length : 14; // B1L (10-bit header length if FD = 1)
- UINT16 VlanTagControl : 2; // VTIR
-
- UINT16 Buf2Length : 14; // B2L
- UINT16 TsoMemoryWriteDisable : 1; // TMWD
- UINT16 InterruptOnCompletion : 1; // IOC
-
- // TDES3
-
- UINT32 TcpPayloadLength : 18; // TPL
- UINT32 TcpSegmentationEnable : 1; // TSE = 0
- UINT32 TcpHeaderLength : 4; // TCP/UDP header length (must be 2 for UDP)
- UINT32 SourceAddressInsertionControl : 3; // SAIC
- UINT32 Reserved26 : 2; // CPC, ignored when TSE = 1
- UINT32 LastDescriptor : 1; // LD
- UINT32 FirstDescriptor : 1; // FD
- UINT32 ContextType : 1; // CTXT = 0
- UINT32 Own : 1; // OWN
-
-#if DBG
- UINT32 FragmentIndex;
- UINT32 PacketIndex;
-#endif
-};
-static_assert(sizeof(TxDescriptorReadTso) == TX_DESCRIPTOR_SIZE);
-
-struct TxDescriptorWrite
-{
- // TDES0, TDES1
-
- UINT32 TimestampLow; // TTSL
- UINT32 TimestampHigh; // TTSH
-
- // TDES2
-
- UINT32 Reserved;
-
- // TDES3
-
- UINT8 IpHeaderError : 1; // IHE
- UINT8 DeferredBit : 1; // DB
- UINT8 UnderflowError : 1; // UF
- UINT8 ExcessiveDeferral : 1; // ED
- UINT8 CollisionCount : 4; // CC
-
- UINT8 ExcessiveCollision : 1; // EC
- UINT8 LateCollision : 1; // LC
- UINT8 NoCarrier : 1; // NC
- UINT8 LossOfCarrier : 1; // LC
- UINT8 PayloadChecksumError : 1; // PCE
- UINT8 PacketFlushed : 1; // PF
- UINT8 JabberTimeout : 1; // JT
- UINT8 ErrorSummary : 1; // ES
-
- UINT8 EccUncorrectableError : 1; // EUE
- UINT8 TimestampStatus : 1; // TTSS
- UINT8 Reserved18 : 5;
- UINT8 DescriptorError : 1; // DE
-
- UINT8 Reserved24 : 4;
- UINT8 LastDescriptor : 1; // LD
- UINT8 FirstDescriptor : 1; // FD
- UINT8 ContextType : 1; // CTXT = 0
- UINT8 Own : 1; // OWN
-
-#if DBG
- UINT32 FragmentIndex;
- UINT32 PacketIndex;
-#endif
-};
-static_assert(sizeof(TxDescriptorWrite) == TX_DESCRIPTOR_SIZE);
-
-struct TxDescriptorContext
-{
- // TDES0, TDES1
-
- UINT32 TimestampLow; // TTSL
- UINT32 TimestampHigh; // TTSH
-
- // TDES2
-
- UINT16 MaximumSegmentSize : 14; // MSS
- UINT16 Reserved14 : 2;
-
- UINT16 InnerVlanTag; // IVT
-
- // TDES3
-
- UINT16 VlanTag; // VT
-
- UINT8 VlanTagValid : 1; // VLTV
- UINT8 InnerVlanTagValid : 1; // IVLTV
- UINT8 InnverVlanTagControl : 2; // IVTIR
- UINT8 Reserved20 : 3;
- UINT8 DescriptorError : 1; // DE
-
- UINT8 Reserved24 : 2;
- UINT8 OneStepInputOrMssValid : 1; // TCMSSV
- UINT8 OneStepEnable : 1; // OSTC
- UINT8 Reserved28 : 2;
- UINT8 ContextType : 1; // CTXT = 1
-
-#if DBG
- UINT32 FragmentIndex;
- UINT32 PacketIndex;
-#endif
-};
-static_assert(sizeof(TxDescriptorContext) == TX_DESCRIPTOR_SIZE);
-
-union TxDescriptor
-{
- TxDescriptorRead Read; // When read, TSE = 0, CTXT = 0.
- TxDescriptorReadTso ReadTso;// When read, TSE = 1, CTXT = 0.
- TxDescriptorWrite Write; // When write, CTXT = 0.
- TxDescriptorContext Context;// When CTXT = 1.
- UINT32 All[DESCRIPTOR_ALIGN / sizeof(UINT32)];
-};
-static_assert(sizeof(TxDescriptor) == DESCRIPTOR_ALIGN);
-
-struct RxDescriptorRead
-{
- // RDES0, RDES1
-
- UINT32 Buf1ApLow; // BUF1AP
- UINT32 Buf1ApHigh; // BUF1AP
-
- // RDES2
-
- UINT32 Buf2Ap; // BUF2AP
-
- // RDES3
-
- UINT16 Reserved0;
- UINT8 Reserved16;
-
- UINT8 Buf1Valid : 1; // BUF1V
- UINT8 Buf2Valid : 1; // BUF2V
- UINT8 Reserved26 : 4;
- UINT8 InterruptOnCompletion : 1; // IOC
- UINT8 Own : 1; // OWN
-
-#if DBG
- UINT32 FragmentIndex;
-#endif
-};
-static_assert(sizeof(RxDescriptorRead) == RX_DESCRIPTOR_SIZE);
-
-enum RxPayloadType : UINT8
-{
- RxPayloadTypeUnknown = 0,
- RxPayloadTypeUdp,
- RxPayloadTypeTcp,
- RxPayloadTypeIcmp,
- RxPayloadTypeIgmp,
- RxPayloadTypeAvUntaggedControl,
- RxPayloadTypeAvTaggedData,
- RxPayloadTypeAvTaggedControl,
-};
-
-struct RxDescriptorWrite
-{
- // RDES0
-
- UINT16 OuterVlanTag; // OVT
- UINT16 InnerVlanTag; // IVT
-
- // RDES1
-
- RxPayloadType PayloadType : 3; // PT
- UINT8 IPHeaderError : 1; // IPHE
- UINT8 IPv4HeaderPresent : 1; // IPV4
- UINT8 IPv6HeaderPresent : 1; // IPV6
- UINT8 IPChecksumBypassed : 1; // IPCB
- UINT8 IPPayloadError : 1; // IPCE
-
- UINT8 PtpMessageType : 4; // PMT
- UINT8 PtpPacketType : 1; // PFT
- UINT8 PtpVersion : 1; // PV
- UINT8 TimestampAvailable : 1; // TSA
- UINT8 TimestampDropped : 1; // TD
-
- UINT16 OamSubtype; // OPC - OAM sub-type and code, or MAC control packet opcode (based on LengthType).
-
- // RDES2
-
- UINT16 L3L4HeaderLength : 10; // HL
- UINT16 ArpReplyNotGenerated : 1; // ARPNR
- UINT16 Reserved11 : 3;
- UINT16 InnerVlanTagStatus : 1; // ITS
- UINT16 VlanFilterStatus : 1; // OTS
-
- UINT16 SourceFilterFail : 1; // SAF/RXPD, based on Flexible RX Parser enable.
- UINT16 DestinationFilterFail : 1; // DAF/RXPI, based on Flexible RX Parser enable.
- UINT16 HashFilterStatus : 1; // HF
- UINT16 MacAddressMatchHashValue : 8; // MADRM
- UINT16 L3FilterMatch : 1; // L3FM
- UINT16 L4FilterMatch : 1; // L4FM
- UINT16 L3L4FilterNumber : 3; // L3L4FM
-
- // RDES3
-
- UINT16 PacketLength : 15; // PL
- UINT16 ErrorSummary : 1; // ES
-
- UINT8 LengthType : 3; // LT
- UINT8 DribbleBitError : 1; // DE
- UINT8 ReceiveError : 1; // RE
- UINT8 OverflowError : 1; // OE
- UINT8 ReceiveWatchdogTimeout : 1; // RWT
- UINT8 GiantPacket : 1; // GP
-
- UINT8 CrcError : 1; // CE
- UINT8 Rdes0Valid : 1; // RS0V, valid only if LD = 1.
- UINT8 Rdes1Valid : 1; // RS1V, valid only if LD = 1.
- UINT8 Rdes2Valid : 1; // RS2V, valid only if LD = 1.
- UINT8 LastDescriptor : 1; // LD
- UINT8 FirstDescriptor : 1; // FD
- UINT8 ContextType : 1; // CTXT = 0
- UINT8 Own : 1; // OWN
-
-#if DBG
- UINT32 FragmentIndex;
-#endif
-};
-static_assert(sizeof(RxDescriptorWrite) == RX_DESCRIPTOR_SIZE);
-
-struct RxDescriptorContext
-{
- UINT32 TimestampLow; // RSTL
- UINT32 TimestampHigh; // RSTH
- UINT32 Reserved2;
-
- // RDES3
-
- UINT16 Reserved3a;
- UINT8 Reserved3b;
- UINT8 Reserved3c : 5;
- UINT8 DescriptorError : 1; // DE
- UINT8 ContextType : 1; // CTXT = 0
- UINT8 Own : 1; // OWN
-
-#if DBG
- UINT32 FragmentIndex;
-#endif
-};
-static_assert(sizeof(RxDescriptorContext) == RX_DESCRIPTOR_SIZE);
-
-union RxDescriptor
-{
- RxDescriptorRead Read; // When read.
- RxDescriptorWrite Write; // When write, CTXT = 0.
- RxDescriptorContext Context;// When write, CTXT = 1.
- UINT32 All[DESCRIPTOR_ALIGN / sizeof(UINT32)];
-};
-static_assert(sizeof(TxDescriptor) == DESCRIPTOR_ALIGN);
-
-#pragma endregion
-
#pragma warning(pop)
diff --git a/drivers/net/dwc_eqos/rxqueue.cpp b/drivers/net/dwc_eqos/rxqueue.cpp
index 29041f9..5a98be7 100644
--- a/drivers/net/dwc_eqos/rxqueue.cpp
+++ b/drivers/net/dwc_eqos/rxqueue.cpp
@@ -3,6 +3,7 @@
#include "queue_common.h"
#include "device.h"
#include "registers.h"
+#include "descriptors.h"
#include "trace.h"
static_assert(sizeof(RxDescriptor) == QueueDescriptorSize);
@@ -122,9 +123,9 @@ RxQueueAdvance(_In_ NETPACKETQUEUE queue)
if (descWrite.Own)
{
/*
- This sometimes happens with transmit descriptors.
+ This sometimes happens with transmit descriptors (DMA race).
I've never seen it happen with receive descriptors, but if it does, breaking out here
- should take care of it.
+ is the right way to deal with it.
*/
TraceWrite("RxQueueAdvance-own", LEVEL_WARNING,
TraceLoggingUInt32(descIndex, "descIndex"),
diff --git a/drivers/net/dwc_eqos/txqueue.cpp b/drivers/net/dwc_eqos/txqueue.cpp
index a1d7705..f29ecd6 100644
--- a/drivers/net/dwc_eqos/txqueue.cpp
+++ b/drivers/net/dwc_eqos/txqueue.cpp
@@ -3,6 +3,7 @@
#include "queue_common.h"
#include "device.h"
#include "registers.h"
+#include "descriptors.h"
#include "trace.h"
static_assert(sizeof(TxDescriptor) == QueueDescriptorSize);
@@ -138,13 +139,14 @@ TxQueueAdvance(_In_ NETPACKETQUEUE queue)
{
/*
There's a race condition where we see the update to Current_App_TxDesc
- before we see the update to the descriptor. It seems harmless (we
- only use the descriptor for assertions and logging), and a fix for
- this would likely affect performance, so just stop when we see a
- descriptor with the Own bit still set.
-
- This would be a bigger issue if it happened in the Rx path, but
- I've never seen that happen.
+ before we see the update to the descriptor. We don't want to write to
+ the descriptor's memory while the update is in flight, but this is
+ otherwise harmless (we only use the descriptor for assertions and
+ logging), and a fix for this would likely affect performance, so just
+ stop when we see a descriptor with the Own bit still set. We'll
+ process it the next time we're called.
+
+ This doesn't seem to happen in the Rx path.
*/
TraceWrite("TxQueueAdvance-own", LEVEL_VERBOSE,
TraceLoggingUInt32(descIndex2, "descIndex"),
@@ -187,7 +189,7 @@ TxQueueAdvance(_In_ NETPACKETQUEUE queue)
pktIndex = pktNext;
- // Number of EMPTY is (descBegin-1) - descEnd, wrapping around if necessary.
+ // Number of EMPTY is (descBegin-1) - descEnd (wrapping around if necessary).
auto const txChecksumOffload = context->txChecksumOffload;
auto const descEnd = context->descEnd;
auto descEmpty = ((context->descBegin - 1) - descEnd) & descMask;