diff --git a/drivers/net/dwc_eqos/descriptors.h b/drivers/net/dwc_eqos/descriptors.h index d8776dc..fca7785 100644 --- a/drivers/net/dwc_eqos/descriptors.h +++ b/drivers/net/dwc_eqos/descriptors.h @@ -168,6 +168,7 @@ struct TxDescriptorContext UINT8 OneStepEnable : 1; // OSTC UINT8 Reserved28 : 2; UINT8 ContextType : 1; // CTXT = 1 + UINT8 Own : 1; // OWN #if DBG UINT32 FragmentIndex; diff --git a/drivers/net/dwc_eqos/device.cpp b/drivers/net/dwc_eqos/device.cpp index cf9f40c..2abc963 100644 --- a/drivers/net/dwc_eqos/device.cpp +++ b/drivers/net/dwc_eqos/device.cpp @@ -90,7 +90,6 @@ struct DeviceContext UINT32 dpcFatalBusError; // Updated only in DPC. UINT32 rxOwnDescriptors; // Updated only during RxQueueAdvance. UINT32 rxDoneFragments; // Updated only during RxQueueAdvance. - UINT32 txOwnDescriptors; // Updated only during TxQueueAdvance. UINT32 txDoneFragments; // Updated only during TxQueueAdvance. }; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DeviceContext, DeviceGetContext) @@ -593,7 +592,7 @@ DeviceD0Entry( : txFifoSize / QueuesSupported; MacTxFlowCtrl_t txFlowCtrl = {}; - txFlowCtrl.TransmitFlowControlEnable = true; + txFlowCtrl.TransmitFlowControlEnable = context->config.txFlowControl; txFlowCtrl.PauseTime = 0xFFFF; Write32(&context->regs->Mac_Tx_Flow_Ctrl, txFlowCtrl); // TxFlow control, pause time. @@ -617,7 +616,7 @@ DeviceD0Entry( UINT32 const rxFlowControlDeactivate = rxFlowControlActivate + rxFlowControlActivate / 2u; // Unpause when 3/4 or 48KB remains. - Write32(&context->regs->Mac_Rx_Flow_Ctrl, 0x3); // Rx flow control, pause packet detect. + Write32(&context->regs->Mac_Rx_Flow_Ctrl, context->config.rxFlowControl ? 0x3 : 0x0); // Rx flow control, pause packet detect. Write32(&context->regs->Mac_RxQ_Ctrl0, 0x2); // RxQ0 enabled for DCB/generic. MtlRxOperationMode_t rxOperationMode = {}; @@ -626,7 +625,7 @@ DeviceD0Entry( rxOperationMode.ForwardErrorPackets = false; rxOperationMode.ForwardUndersizedGoodPackets = true; rxOperationMode.QueueSize = rxQueueSize / 256u - 1; - rxOperationMode.HardwareFlowControl = rxQueueSize >= 2048; + rxOperationMode.HardwareFlowControl = context->config.rxFlowControl && rxQueueSize >= 2048; rxOperationMode.FlowControlActivate = (rxFlowControlActivate / 512u) - 2u; rxOperationMode.FlowControlDeactivate = (rxFlowControlDeactivate / 512u) - 2u; Write32(&context->regs->Mtl_Q[0].Rx_Operation_Mode, rxOperationMode); @@ -634,13 +633,21 @@ DeviceD0Entry( // MAC configuration. MacConfiguration_t macConfig = {}; - macConfig.DisableCarrierSenseDuringTransmit = true; - macConfig.PacketBurstEnable = true; macConfig.ReceiverEnable = true; macConfig.TransmitterEnable = true; + macConfig.DisableCarrierSenseDuringTransmit = true; + macConfig.DisableReceiveOwn = true; + macConfig.PacketBurstEnable = true; + //macConfig.PadOrCrcStripEnable = true; // Why doesn't this work? + //macConfig.CrcStripEnableForType = true; // Why doesn't this work? macConfig.ChecksumOffloadEnable = context->config.txCoeSel || context->config.rxCoeSel; Write32(&context->regs->Mac_Configuration, macConfig); + Mac_Vlan_Tag_Ctrl_t vlanTagCtrl = {}; + vlanTagCtrl.StripOnReceive = VlanTagStripOnReceive_Always; + vlanTagCtrl.RxStatusEnable = true; + Write32(&context->regs->Mac_Vlan_Tag_Ctrl, vlanTagCtrl); + // Clear any pending interrupts, then unmask them. NT_ASSERT(ReadNoFence8(&context->updateLinkStateBusy) == 0); @@ -707,6 +714,7 @@ DevicePrepareHardware( PHYSICAL_ADDRESS maxPhysicalAddress; auto const context = DeviceGetContext(device); bool configHasMacAddress = false; + ULONG flowControlConfiguration; // Read configuration @@ -746,6 +754,15 @@ DevicePrepareHardware( memcpy(context->currentMacAddress, configAddress.Address, sizeof(context->currentMacAddress)); configHasMacAddress = true; } + + 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 + } } // Configure resources @@ -908,6 +925,14 @@ DevicePrepareHardware( status = STATUS_DEVICE_CONFIGURATION_ERROR; goto Done; } + + if (!context->feature0.SaVlanIns) + { + // Could adapt at runtime if needed, but assume it's present for now. + TraceWrite("DevicePrepareHardware-SaVlanIns-required", LEVEL_ERROR); + status = STATUS_DEVICE_CONFIGURATION_ERROR; + goto Done; + } } // Device Config @@ -925,6 +950,33 @@ DevicePrepareHardware( context->config.rd_osr_lmt = 8; context->config.blen = 0x7; // 0x7 = 4, 8, 16 + switch (flowControlConfiguration) + { + case 0: // Disabled + context->config.txFlowControl = false; + context->config.rxFlowControl = false; + break; + case 1: // TxEnabled + context->config.txFlowControl = true; + context->config.rxFlowControl = false; + break; + case 2: // RxEnabled + context->config.txFlowControl = false; + context->config.rxFlowControl = true; + break; + case 3: // TxRxEnabled + case 4: // AutoNegotiate + context->config.txFlowControl = true; + context->config.rxFlowControl = true; + break; + default: + TraceWrite("QueryFlowControl-bad-value", LEVEL_WARNING, + TraceLoggingUInt32(flowControlConfiguration, "value")); + context->config.txFlowControl = true; + context->config.rxFlowControl = true; + break; + } + auto const deviceObject = WdfDeviceWdmGetPhysicalDevice(device); PACPI_EVAL_OUTPUT_BUFFER outputBuffer = nullptr; ACPI_METHOD_ARGUMENT const UNALIGNED* properties = nullptr; @@ -1139,7 +1191,7 @@ DevicePrepareHardware( NET_ADAPTER_TX_CAPABILITIES txCaps; NET_ADAPTER_TX_CAPABILITIES_INIT_FOR_DMA(&txCaps, &dmaCaps, QueuesSupported); - txCaps.MaximumNumberOfFragments = QueueDescriptorMinCount - 1; + 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. @@ -1181,6 +1233,12 @@ DevicePrepareHardware( NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES_INIT(&rxChecksumCaps, AdapterOffloadSetRxChecksum); NetAdapterOffloadSetRxChecksumCapabilities(context->adapter, &rxChecksumCaps); + + NET_ADAPTER_OFFLOAD_IEEE8021Q_TAG_CAPABILITIES ieee8021qCaps; + NET_ADAPTER_OFFLOAD_IEEE8021Q_TAG_CAPABILITIES_INIT(&ieee8021qCaps, + NetAdapterOffloadIeee8021PriorityTaggingFlag | + NetAdapterOffloadIeee8021VlanTaggingFlag); + NetAdapterOffloadSetIeee8021qTagCapabilities(context->adapter, &ieee8021qCaps); } // Initialize adapter. @@ -1325,11 +1383,9 @@ _IRQL_requires_max_(DISPATCH_LEVEL) void DeviceAddStatisticsTxQueue( _Inout_ DeviceContext* context, - UINT32 ownDescriptors, UINT32 doneFragments) { // DISPATCH_LEVEL - context->txOwnDescriptors += ownDescriptors; context->txDoneFragments += doneFragments; } @@ -1544,7 +1600,6 @@ PerfDataInit( data->DpcFatalBusError = context->dpcFatalBusError; data->RxOwnDescriptors = context->rxOwnDescriptors; data->RxDoneFragments = context->rxDoneFragments; - data->TxOwnDescriptors = context->txOwnDescriptors; data->TxDoneFragments = context->txDoneFragments; } diff --git a/drivers/net/dwc_eqos/device.h b/drivers/net/dwc_eqos/device.h index 298da46..bcc1739 100644 --- a/drivers/net/dwc_eqos/device.h +++ b/drivers/net/dwc_eqos/device.h @@ -19,6 +19,8 @@ struct DeviceConfig UINT8 wr_osr_lmt; // AXIC\snps,wr_osr_lmt (default = 4). UINT8 rd_osr_lmt; // AXIC\snps,rd_osr_lmt (default = 8). 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). }; // Referenced in driver.cpp DriverEntry. @@ -66,5 +68,4 @@ _IRQL_requires_max_(DISPATCH_LEVEL) void DeviceAddStatisticsTxQueue( _Inout_ DeviceContext* context, - UINT32 ownDescriptors, UINT32 doneFragments); diff --git a/drivers/net/dwc_eqos/driver.cpp b/drivers/net/dwc_eqos/driver.cpp index 379c529..12af233 100644 --- a/drivers/net/dwc_eqos/driver.cpp +++ b/drivers/net/dwc_eqos/driver.cpp @@ -1,15 +1,14 @@ #include "precomp.h" -#include "device.h" // DeviceAdd +#include "device.h" #include "trace.h" /* Possible areas for improvement: -- Run against network test suites and fix any issues. - Jumbo frames. -- Configuration in registry (e.g. flow control, speed, duplex). - Tx segmentation offload. -- Wake-on-LAN. -- ARP offload. +- Run against network test suites and fix any issues. +- Power control, wake-on-LAN, ARP offload. +- Configure speed, duplex in Ndi\params. - Multi-queue support? */ diff --git a/drivers/net/dwc_eqos/dwc_eqos.inf b/drivers/net/dwc_eqos/dwc_eqos.inf index 99fea27..24e7475 100644 --- a/drivers/net/dwc_eqos/dwc_eqos.inf +++ b/drivers/net/dwc_eqos/dwc_eqos.inf @@ -77,52 +77,44 @@ HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" [DWCEQOS_AddReg_Ndi_params] -HKR, Ndi\params\NetworkAddress, ParamDesc, 0, %NetworkAddress% -HKR, Ndi\params\NetworkAddress, type, 0, "edit" -HKR, Ndi\params\NetworkAddress, default, 0, "" -HKR, Ndi\params\NetworkAddress, LimitText, 0, "12" -HKR, Ndi\params\NetworkAddress, UpperCase, 0, "1" -HKR, Ndi\params\NetworkAddress, Optional, 0, "1" - -HKR, Ndi\params\*IPChecksumOffloadIPv4, ParamDesc, 0, %IPChksumOffV4% -HKR, Ndi\params\*IPChecksumOffloadIPv4, default, 0, "3" -HKR, Ndi\params\*IPChecksumOffloadIPv4, type, 0, "enum" -HKR, Ndi\params\*IPChecksumOffloadIPv4\enum, "0", 0, %Disabled% -HKR, Ndi\params\*IPChecksumOffloadIPv4\enum, "1", 0, %TxEnabled% -HKR, Ndi\params\*IPChecksumOffloadIPv4\enum, "2", 0, %RxEnabled% -HKR, Ndi\params\*IPChecksumOffloadIPv4\enum, "3", 0, %RxTxEnabled% - -HKR, Ndi\params\*TCPChecksumOffloadIPv4, ParamDesc, 0, %TCPChksumOffV4% -HKR, Ndi\params\*TCPChecksumOffloadIPv4, default, 0, "3" -HKR, Ndi\params\*TCPChecksumOffloadIPv4, type, 0, "enum" -HKR, Ndi\params\*TCPChecksumOffloadIPv4\enum, "0", 0, %Disabled% -HKR, Ndi\params\*TCPChecksumOffloadIPv4\enum, "1", 0, %TxEnabled% -HKR, Ndi\params\*TCPChecksumOffloadIPv4\enum, "2", 0, %RxEnabled% -HKR, Ndi\params\*TCPChecksumOffloadIPv4\enum, "3", 0, %RxTxEnabled% - -HKR, Ndi\params\*UDPChecksumOffloadIPv4, ParamDesc, 0, %UDPChksumOffV4% -HKR, Ndi\params\*UDPChecksumOffloadIPv4, default, 0, "3" -HKR, Ndi\params\*UDPChecksumOffloadIPv4, type, 0, "enum" -HKR, Ndi\params\*UDPChecksumOffloadIPv4\enum, "0", 0, %Disabled% -HKR, Ndi\params\*UDPChecksumOffloadIPv4\enum, "1", 0, %TxEnabled% -HKR, Ndi\params\*UDPChecksumOffloadIPv4\enum, "2", 0, %RxEnabled% -HKR, Ndi\params\*UDPChecksumOffloadIPv4\enum, "3", 0, %RxTxEnabled% - -HKR, Ndi\params\*TCPChecksumOffloadIPv6, ParamDesc, 0, %TCPChksumOffV6% -HKR, Ndi\params\*TCPChecksumOffloadIPv6, default, 0, "3" -HKR, Ndi\params\*TCPChecksumOffloadIPv6, type, 0, "enum" -HKR, Ndi\params\*TCPChecksumOffloadIPv6\enum, "0", 0, %Disabled% -HKR, Ndi\params\*TCPChecksumOffloadIPv6\enum, "1", 0, %TxEnabled% -HKR, Ndi\params\*TCPChecksumOffloadIPv6\enum, "2", 0, %RxEnabled% -HKR, Ndi\params\*TCPChecksumOffloadIPv6\enum, "3", 0, %RxTxEnabled% - -HKR, Ndi\params\*UDPChecksumOffloadIPv6, ParamDesc, 0, %UDPChksumOffV6% -HKR, Ndi\params\*UDPChecksumOffloadIPv6, default, 0, "3" -HKR, Ndi\params\*UDPChecksumOffloadIPv6, type, 0, "enum" -HKR, Ndi\params\*UDPChecksumOffloadIPv6\enum, "0", 0, %Disabled% -HKR, Ndi\params\*UDPChecksumOffloadIPv6\enum, "1", 0, %TxEnabled% -HKR, Ndi\params\*UDPChecksumOffloadIPv6\enum, "2", 0, %RxEnabled% -HKR, Ndi\params\*UDPChecksumOffloadIPv6\enum, "3", 0, %RxTxEnabled% +HKR, Ndi\params\NetworkAddress, ParamDesc, 0, %NetworkAddress% +HKR, Ndi\params\NetworkAddress, type, 0, "edit" +HKR, Ndi\params\NetworkAddress, default, 0, "" +HKR, Ndi\params\NetworkAddress, LimitText, 0, "12" +HKR, Ndi\params\NetworkAddress, UpperCase, 0, "1" +HKR, Ndi\params\NetworkAddress, Optional, 0, "1" + +HKR, Ndi\params\*FlowControl, ParamDesc, 0, %FlowControl% +HKR, Ndi\params\*FlowControl, default, 0, "3" +HKR, Ndi\params\*FlowControl, type, 0, "enum" +HKR, Ndi\params\*FlowControl\enum, "0", 0, %Disabled% +HKR, Ndi\params\*FlowControl\enum, "1", 0, %TxEnabled% +HKR, Ndi\params\*FlowControl\enum, "2", 0, %RxEnabled% +HKR, Ndi\params\*FlowControl\enum, "3", 0, %TxRxEnabled% + +HKR, Ndi\Params\*PriorityVLANTag, ParamDesc, 0, %PriorityVlanTag% +HKR, Ndi\Params\*PriorityVLANTag, Default, 0, "3" +HKR, Ndi\Params\*PriorityVLANTag, Type, 0, "enum" +HKR, Ndi\Params\*PriorityVLANTag\enum, "0", 0, %Disabled% +HKR, Ndi\Params\*PriorityVLANTag\enum, "1", 0, %PriorityEnabled% +HKR, Ndi\Params\*PriorityVLANTag\enum, "2", 0, %VlanEnabled% +HKR, Ndi\Params\*PriorityVLANTag\enum, "3", 0, %PriorityVlanEnabled% + +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv4, ParamDesc, 0, %TCPUDPChecksumOffloadIPv4% +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv4, default, 0, "3" +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv4, type, 0, "enum" +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv4\enum, "0", 0, %Disabled% +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv4\enum, "1", 0, %TxEnabled% +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv4\enum, "2", 0, %RxEnabled% +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv4\enum, "3", 0, %TxRxEnabled% + +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv6, ParamDesc, 0, %TCPUDPChecksumOffloadIPv6% +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv6, default, 0, "3" +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv6, type, 0, "enum" +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv6\enum, "0", 0, %Disabled% +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv6\enum, "1", 0, %TxEnabled% +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv6\enum, "2", 0, %RxEnabled% +HKR, Ndi\params\*TCPUDPChecksumOffloadIPv6\enum, "3", 0, %TxRxEnabled% [DWCEQOS_Device.NT.Services] AddService = %ServiceName%, 2, DWCEQOS_AddService, DWCEQOS_AddService_EventLog @@ -153,19 +145,21 @@ KmdfLibraryVersion = $KMDFVERSION$ [Strings] ProviderName = "Open Source" -NetworkAddress = "Network Address" RKCP = "Rockchip" DWCEQOS.DeviceDesc = "Synopsys DesignWare Ethernet Quality of Service (GMAC)" DWCEQOS.ServiceDesc = "DesignWare Ethernet" -IPChksumOffV4 = "IPv4 Checksum Offload" -TCPChksumOffV4 = "TCP Checksum Offload (IPv4)" -UDPChksumOffV4 = "UDP Checksum Offload (IPv4)" -TCPChksumOffV6 = "TCP Checksum Offload (IPv6)" -UDPChksumOffV6 = "UDP Checksum Offload (IPv6)" +NetworkAddress = "Network Address" +FlowControl = "Flow Control" +PriorityVlanTag = "Packet Priority & VLAN" +TCPUDPChecksumOffloadIPv4 = "TCP/UDP Checksum Offload (IPv4)" +TCPUDPChecksumOffloadIPv6 = "TCP/UDP Checksum Offload (IPv6)" Disabled = "Disabled" TxEnabled = "Tx Enabled" RxEnabled = "Rx Enabled" -RxTxEnabled = "Rx & Tx Enabled" +TxRxEnabled = "Tx and Rx Enabled" +PriorityEnabled = "Packet Priority Enabled" +VlanEnabled = "VLAN Enabled" +PriorityVlanEnabled = "Packet Priority & VLAN Enabled" ; Not localized ServiceName = "dwc_eqos" diff --git a/drivers/net/dwc_eqos/dwc_eqos_perf.man b/drivers/net/dwc_eqos/dwc_eqos_perf.man index 832a077..4a31a2b 100644 --- a/drivers/net/dwc_eqos/dwc_eqos_perf.man +++ b/drivers/net/dwc_eqos/dwc_eqos_perf.man @@ -452,21 +452,12 @@ type="perf_counter_rawcount" uri="uri:opensource/dwc_eqos/perf/debug/RxDoneFragments" /> - diff --git a/drivers/net/dwc_eqos/dwc_eqos_perf_data.h b/drivers/net/dwc_eqos/dwc_eqos_perf_data.h index c562940..1bd05c1 100644 --- a/drivers/net/dwc_eqos/dwc_eqos_perf_data.h +++ b/drivers/net/dwc_eqos/dwc_eqos_perf_data.h @@ -30,7 +30,6 @@ struct PERF_DEBUG_DATA UINT32 DpcFatalBusError; UINT32 RxOwnDescriptors; UINT32 RxDoneFragments; - UINT32 TxOwnDescriptors; UINT32 TxDoneFragments; }; diff --git a/drivers/net/dwc_eqos/precomp.h b/drivers/net/dwc_eqos/precomp.h index bf51ec8..f555bce 100644 --- a/drivers/net/dwc_eqos/precomp.h +++ b/drivers/net/dwc_eqos/precomp.h @@ -8,6 +8,7 @@ #pragma warning(pop) #include +#include #include #include #include diff --git a/drivers/net/dwc_eqos/registers.h b/drivers/net/dwc_eqos/registers.h index 17323da..1c7500b 100644 --- a/drivers/net/dwc_eqos/registers.h +++ b/drivers/net/dwc_eqos/registers.h @@ -639,6 +639,43 @@ union MacPacketFilter_t }; }; +enum VlanTagStripOnReceive : UINT8 +{ + VlanTagStripOnReceive_Never, + VlanTagStripOnReceive_IfFilterPasses, + VlanTagStripOnReceive_IfFilterFails, + VlanTagStripOnReceive_Always, +}; + +union Mac_Vlan_Tag_Ctrl_t +{ + UINT32 Value32; + struct + { + UINT8 OperationBusy : 1; // OB + UINT8 CommandType : 1; // CT, 0 = write, 1 = read. + UINT8 Offset : 5; // OFS + UINT8 Reserved7 : 1; + + UINT8 Reserved8; + + UINT8 Reserved16 : 1; + UINT8 InverseMatchEnable : 1; // VTIM + UINT8 SvlanEnable : 1; // ESVL + UINT8 Reserved19 : 2; + VlanTagStripOnReceive StripOnReceive : 2; // EVLS + UINT8 Reserved23 : 1; + + UINT8 RxStatusEnable : 1; // EVLRXS + UINT8 HashTableMatchEnable : 1; // VTHM + UINT8 DoubleVlanEnable : 1; // EDVLP + UINT8 InnerEnable : 1; // ERIVLT + VlanTagStripOnReceive InnerStripOnReceive : 2; // EIVLS + UINT8 Reserved30 : 1; + UINT8 InnerRxStatusEnable : 1; // EIVLRXS + }; +}; + union MacInterruptStatus_t { UINT32 Value32; @@ -924,7 +961,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. - ULONG Mac_Vlan_Tag_Ctrl; + Mac_Vlan_Tag_Ctrl_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 diff --git a/drivers/net/dwc_eqos/rxqueue.cpp b/drivers/net/dwc_eqos/rxqueue.cpp index 5a98be7..b0a21d3 100644 --- a/drivers/net/dwc_eqos/rxqueue.cpp +++ b/drivers/net/dwc_eqos/rxqueue.cpp @@ -18,6 +18,7 @@ struct RxQueueContext WDFCOMMONBUFFER descBuffer; RxDescriptor* descVirtual; PHYSICAL_ADDRESS descPhysical; + NET_EXTENSION packetIeee8021Q; NET_EXTENSION packetChecksum; NET_EXTENSION fragmentLogical; UINT32 descCount; // A power of 2 between QueueDescriptorMinCount and QueueDescriptorMaxCount. @@ -171,6 +172,16 @@ RxQueueAdvance(_In_ NETPACKETQUEUE queue) NT_ASSERT(descWrite.PacketLength >= 4); // PacketLength includes CRC frag->ValidLength = descWrite.PacketLength - 4; + if (descWrite.Rdes0Valid && descWrite.OuterVlanTag != 0) + { + NET_PACKET_IEEE8021Q tag = {}; + tag.PriorityCodePoint = descWrite.OuterVlanTag >> 13; + tag.VlanIdentifier = descWrite.OuterVlanTag; + + auto const ieee8021Q = NetExtensionGetPacketIeee8021Q(&context->packetIeee8021Q, pktIndex); + *ieee8021Q = tag; + } + // If checksum offload is disabled by hardware then no IP headers will be // detected. If checksum offload is disabled by software then NetAdapterCx // will ignore our evaluation. @@ -416,6 +427,12 @@ RxQueueCreate( NET_EXTENSION_QUERY query; + NET_EXTENSION_QUERY_INIT(&query, + NET_PACKET_EXTENSION_IEEE8021Q_NAME, + NET_PACKET_EXTENSION_IEEE8021Q_VERSION_1, + NetExtensionTypePacket); + NetRxQueueGetExtension(queue, &query, &context->packetIeee8021Q); + NET_EXTENSION_QUERY_INIT(&query, NET_PACKET_EXTENSION_CHECKSUM_NAME, NET_PACKET_EXTENSION_CHECKSUM_VERSION_1, diff --git a/drivers/net/dwc_eqos/txqueue.cpp b/drivers/net/dwc_eqos/txqueue.cpp index f29ecd6..a15a2bc 100644 --- a/drivers/net/dwc_eqos/txqueue.cpp +++ b/drivers/net/dwc_eqos/txqueue.cpp @@ -18,17 +18,21 @@ struct TxQueueContext WDFCOMMONBUFFER descBuffer; TxDescriptor* descVirtual; PHYSICAL_ADDRESS descPhysical; + NET_EXTENSION packetIeee8021Q; NET_EXTENSION packetChecksum; NET_EXTENSION fragmentLogical; UINT32 descCount; // A power of 2 between QueueDescriptorMinCount and QueueDescriptorMaxCount. UINT8 txPbl; bool txChecksumOffload; + UINT16 lastVlanTag; UINT32 descBegin; // Start of the TRANSMIT region. UINT32 descEnd; // End of the TRANSMIT region, start of the EMPTY region. }; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(TxQueueContext, TxQueueGetContext) +#if DBG + // Gets channelRegs->Current_App_TxDesc, converted to an index. static UINT32 GetDescNext(_In_ TxQueueContext* context) @@ -38,6 +42,8 @@ GetDescNext(_In_ TxQueueContext* context) return QueueDescriptorAddressToIndex(current, context->descPhysical, context->descCount); } +#endif // DBG + // Sets channelRegs->TxDesc_Tail_Pointer to the physical address of the descriptor at the given index. static void SetDescEnd( @@ -58,6 +64,7 @@ TxQueueStart(_In_ NETPACKETQUEUE queue) // PASSIVE_LEVEL, nonpaged (resume path) auto const context = TxQueueGetContext(queue); + context->lastVlanTag = 0; // Make no assumptions about the device's current vlan tag. context->descBegin = 0; context->descEnd = 0; @@ -80,123 +87,121 @@ TxQueueStart(_In_ NETPACKETQUEUE queue) TraceEntryExit(TxQueueStart, LEVEL_INFO); } +// Starting at pktIndex, scan forward until we reach packetRing->NextIndex or a +// non-ignored packet. If we reach a non-ignored packet, sets *pktLastFrag to the last +// fragment of the found packet and returns the packet's index. Otherwise, sets +// *pktLastFrag to 0xFFFFFFFF and returns packetRing->NextIndex. +static UINT32 +SkipIgnorePackets(UINT32 pktIndex, _In_ TxQueueContext const* context, _Out_ UINT32* pktLastFrag) +{ + // DISPATCH_LEVEL + auto const pktNext = context->packetRing->NextIndex; + for (; pktIndex != pktNext; pktIndex = NetRingIncrementIndex(context->packetRing, pktIndex)) + { + auto const pkt = NetRingGetPacketAtIndex(context->packetRing, pktIndex); + if (!pkt->Ignore) + { + NT_ASSERT(pkt->FragmentCount != 0); + *pktLastFrag = NetRingAdvanceIndex(context->fragmentRing, pkt->FragmentIndex, pkt->FragmentCount - 1u); + return pktIndex; + } + } + + *pktLastFrag = 0xFFFFFFFF; + return pktNext; +} + static EVT_PACKET_QUEUE_ADVANCE TxQueueAdvance; static void TxQueueAdvance(_In_ NETPACKETQUEUE queue) { // DISPATCH_LEVEL auto const context = TxQueueGetContext(queue); - auto const pktBegin = context->packetRing->BeginIndex; - auto const pktNext = context->packetRing->NextIndex; - auto const pktEnd = context->packetRing->EndIndex; auto const descMask = context->descCount - 1u; - UINT32 descIndex, pktIndex, fragIndex; - UINT32 ownDescriptors = 0, doneFrags = 0, queuedFrags = 0; + auto const descEnd = context->descEnd; + UINT32 descIndex, pktIndex, pktLastFrag, fragIndex; + UINT32 doneFrags = 0, queuedFrags = 0; /* Packet indexes: [pktBegin] old [pktNext] new [pktEnd] owned by NetAdapterCx [pktBegin] Descriptor indexes: - [descBegin] TRANSMITTED [descNext] TRANSMITTING [descEnd] EMPTY [descBegin-1] + [descBegin] TRANSMITTED TRANSMITTING [descEnd] EMPTY [descBegin-1] */ // Indicate transmitted packets. - pktIndex = pktBegin; + // Process any descriptors that the adapter has handed back to us. + // Release the corresponding fragments and packets. + pktIndex = SkipIgnorePackets(context->packetRing->BeginIndex, context, &pktLastFrag); fragIndex = context->fragmentRing->BeginIndex; - - auto const descNext = GetDescNext(context); - descIndex = context->descBegin; - auto descReady = (descNext - descIndex) & descMask; // Number of descriptors ready to be indicated. - while (descIndex != descNext) + for (descIndex = context->descBegin; descIndex != descEnd; descIndex = (descIndex + 1) & descMask) { - NT_ASSERT(pktIndex != pktNext); + NT_ASSERT(pktIndex != context->packetRing->NextIndex); + NT_ASSERT(pktLastFrag != 0xFFFFFFFF); - auto const pkt = NetRingGetPacketAtIndex(context->packetRing, pktIndex); - auto const fragmentCount = pkt->FragmentCount; - if (!pkt->Ignore) + auto const& desc = context->descVirtual[descIndex]; + auto const descWrite = desc.Write; + + if (descWrite.Own) { - NT_ASSERT(fragmentCount != 0); + // Descriptor is still owned by the DMA engine. + break; + } - if (fragmentCount > descReady) - { - break; - } + NT_ASSERT(descWrite.PacketIndex == pktIndex); + NT_ASSERT(descWrite.FragmentIndex == fragIndex); - for (unsigned i = 0; i != fragmentCount; i += 1) - { - auto const descIndex2 = (descIndex + i) & descMask; - NT_ASSERT(descIndex2 != descNext); + if (descWrite.ContextType) + { + // Ignore context descriptors. + continue; + } - auto const& desc = context->descVirtual[descIndex2]; - auto const descWrite = desc.Write; - NT_ASSERT(descWrite.PacketIndex == pktIndex); - NT_ASSERT(descWrite.FragmentIndex == NetRingAdvanceIndex(context->fragmentRing, pkt->FragmentIndex, i)); + if (descWrite.ErrorSummary || + descWrite.ContextType || + descWrite.DescriptorError || + (descWrite.LastDescriptor != 0) != (fragIndex == pktLastFrag)) + { + TraceWrite("TxQueueAdvance-error", LEVEL_ERROR, + TraceLoggingUInt32(descIndex), + TraceLoggingHexInt32(reinterpret_cast(&descWrite)[3], "TDES3"), + TraceLoggingUInt32(fragIndex), + TraceLoggingUInt32(pktLastFrag)); + } - // Descriptor is still owned by the DMA engine? - if (descWrite.Own) - { - /* - There's a race condition where we see the update to Current_App_TxDesc - 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"), - TraceLoggingHexInt32(reinterpret_cast(&descWrite)[3], "TDES3"), - TraceLoggingUInt32(i, "fragment"), - TraceLoggingUInt32(fragmentCount)); - ownDescriptors = 1; - goto DoneIndicating; - } - else if ( - descWrite.ErrorSummary || - descWrite.ContextType || - descWrite.DescriptorError || - (descWrite.LastDescriptor != 0) != (i == fragmentCount - 1u)) - { - TraceWrite("TxQueueAdvance-error", LEVEL_ERROR, - TraceLoggingUInt32(descIndex2, "descIndex"), - TraceLoggingHexInt32(reinterpret_cast(&descWrite)[3], "TDES3"), - TraceLoggingUInt32(i, "fragment"), - TraceLoggingUInt32(fragmentCount)); - } - } + // Non-context descriptors map one-to-one with fragments. - doneFrags += fragmentCount; - descReady -= fragmentCount; - descIndex = (descIndex + fragmentCount) & descMask; + if (fragIndex == pktLastFrag) + { + // Packet is complete. Move to the next one. + pktIndex = SkipIgnorePackets(NetRingIncrementIndex(context->packetRing, pktIndex), context, &pktLastFrag); } - pktIndex = NetRingIncrementIndex(context->packetRing, pktIndex); - fragIndex = NetRingAdvanceIndex(context->fragmentRing, pkt->FragmentIndex, fragmentCount); + // Fragment is complete. Move to the next one. + fragIndex = NetRingIncrementIndex(context->fragmentRing, fragIndex); } -DoneIndicating: - + // Return the completed packets and fragments to NetAdapterCx. context->packetRing->BeginIndex = pktIndex; context->fragmentRing->BeginIndex = fragIndex; - context->descBegin = descIndex; + + auto const descBegin = descIndex; + context->descBegin = descBegin; // Fill more descriptors. - pktIndex = pktNext; + pktIndex = context->packetRing->NextIndex; // Number of EMPTY is (descBegin-1) - descEnd (wrapping around if necessary). + auto const pktEnd = context->packetRing->EndIndex; auto const txChecksumOffload = context->txChecksumOffload; - auto const descEnd = context->descEnd; - auto descEmpty = ((context->descBegin - 1) - descEnd) & descMask; + auto descEmpty = (descBegin - 1 - descEnd) & descMask; descIndex = descEnd; while (descEmpty != 0) { - NT_ASSERT(descIndex != ((context->descBegin - 1) & descMask)); + NT_ASSERT(descIndex != ((descBegin - 1) & descMask)); if (pktIndex == pktEnd) { @@ -220,11 +225,46 @@ TxQueueAdvance(_In_ NETPACKETQUEUE queue) : checksum.Layer3 ? TxChecksumInsertionEnabledHeaderOnly : TxChecksumInsertionDisabled; - auto const fragmentCount = pkt->FragmentCount; + UINT32 const fragmentCount = pkt->FragmentCount; NT_ASSERT(fragmentCount != 0); - if (fragmentCount > descEmpty) + + auto const ieee8021Q = NetExtensionGetPacketIeee8021Q(&context->packetIeee8021Q, pktIndex); + if (ieee8021Q->TxTagging != 0) { - break; + UINT16 const newTag = (ieee8021Q->PriorityCodePoint << 13) | ieee8021Q->VlanIdentifier; + NT_ASSERT(newTag != 0); + if (newTag == context->lastVlanTag) + { + goto NoContextPacket; + } + + if (fragmentCount + 1 > descEmpty) + { + break; + } + + TxDescriptorContext descCtx = {}; + descCtx.VlanTag = newTag; + descCtx.VlanTagValid = true; + descCtx.ContextType = true; + descCtx.Own = true; +#if DBG + descCtx.PacketIndex = pktIndex; + descCtx.FragmentIndex = fragIndex; +#endif + + context->descVirtual[descIndex].Context = descCtx; + descIndex = (descIndex + 1) & descMask; + descEmpty -= 1; + } + else + { + NoContextPacket: + + if (fragmentCount > descEmpty) + { + break; + } } UINT32 frameLength = 0; @@ -263,24 +303,22 @@ TxQueueAdvance(_In_ NETPACKETQUEUE queue) fragIndex = NetRingIncrementIndex(context->fragmentRing, fragIndex); queuedFrags += 1; } + + descEmpty -= fragmentCount; } pktIndex = NetRingIncrementIndex(context->packetRing, pktIndex); } - // In some error cases, the device may stall until we write to the tail pointer - // again. Write to the tail pointer if there are pending descriptors, even if we - // didn't fill any new ones. - if (descIndex != descNext) + if (descIndex != descEnd) { SetDescEnd(context, descIndex); context->packetRing->NextIndex = pktIndex; } - DeviceAddStatisticsTxQueue(context->deviceContext, ownDescriptors, doneFrags); + DeviceAddStatisticsTxQueue(context->deviceContext, doneFrags); TraceEntryExit(TxQueueAdvance, LEVEL_VERBOSE, - TraceLoggingUInt32(ownDescriptors), TraceLoggingUInt32(doneFrags), TraceLoggingUInt32(queuedFrags)); } @@ -491,6 +529,12 @@ TxQueueCreate( NET_EXTENSION_QUERY query; + NET_EXTENSION_QUERY_INIT(&query, + NET_PACKET_EXTENSION_IEEE8021Q_NAME, + NET_PACKET_EXTENSION_IEEE8021Q_VERSION_1, + NetExtensionTypePacket); + NetTxQueueGetExtension(queue, &query, &context->packetIeee8021Q); + if (context->txChecksumOffload) { NET_EXTENSION_QUERY_INIT(&query,