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;