From 07fa5d6b2ea1b5e8f797ef362b25d9c7e8acca5f Mon Sep 17 00:00:00 2001 From: Doug Cook <45909143+idigdoug@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:00:31 -0800 Subject: [PATCH] dwc_eqos - fix transmitted vlan tags (#40) All transmitted VLAN tags were 0. We weren't setting the VlanInput flag, so when inserting VLAN tags, the adapter was using a global value (0) instead of the value from the descriptor ring. Fix. - Set the VlanInput flag so that inserted VLAN tags are taken from context descriptor. - Add a VLAN ID configuration setting. This is a semi-standard tag, and I couldn't find great details on how it is supposed to work. At present, it just controls the default VLAN tag to use when transmitting. I think some adapters also use it to filter received packets, but I don't think that's a good idea for this driver since NetAdapterCx doesn't support OID_GEN_VLAN_ID. - Update Tx path to handle a default VLAN tag. Ended up cleaning things up a bit so the result is shorter. --- drivers/net/dwc_eqos/device.cpp | 17 +++++++- drivers/net/dwc_eqos/device.h | 1 + drivers/net/dwc_eqos/dwc_eqos.inf | 7 ++++ drivers/net/dwc_eqos/registers.h | 21 +++++++++- drivers/net/dwc_eqos/txqueue.cpp | 70 ++++++++++++------------------- 5 files changed, 70 insertions(+), 46 deletions(-) diff --git a/drivers/net/dwc_eqos/device.cpp b/drivers/net/dwc_eqos/device.cpp index a187787..3a37474 100644 --- a/drivers/net/dwc_eqos/device.cpp +++ b/drivers/net/dwc_eqos/device.cpp @@ -675,6 +675,10 @@ DeviceD0Entry( vlanTagCtrl.RxStatusEnable = true; Write32(&context->regs->Mac_Vlan_Tag_Ctrl, vlanTagCtrl); + MacVlanIncl_t vlanIncl = {}; + vlanIncl.VlanInput = true; // Get packet's VLAN tag from context descriptor. + Write32(&context->regs->Mac_Vlan_Incl, vlanIncl); + MacWatchdogTimeout_t watchdogTimeout = {}; // 0 = 2KB, 1 = 3KB, ... 14 = 16KB, 15 = Reserved. // jumboFrame value doesn't include VLAN or CRC, so add 8. @@ -752,6 +756,7 @@ DevicePrepareHardware( bool configHasMacAddress = false; ULONG flowControlConfiguration; ULONG jumboPacketConfiguration; + ULONG vlanIdConfiguration; // Read configuration @@ -809,6 +814,15 @@ DevicePrepareHardware( TraceLoggingNTStatus(status)); jumboPacketConfiguration = JumboPacketMin; } + + DECLARE_CONST_UNICODE_STRING(VlanID_Name, L"VlanID"); + status = NetConfigurationQueryUlong(configuration, NET_CONFIGURATION_QUERY_ULONG_NO_FLAGS, &VlanID_Name, &vlanIdConfiguration); + if (!NT_SUCCESS(status)) + { + TraceWrite("QueryVlanID-not-found", LEVEL_VERBOSE, + TraceLoggingNTStatus(status)); + vlanIdConfiguration = 0; + } } // Configure resources @@ -1021,6 +1035,7 @@ DevicePrepareHardware( jumboPacketConfiguration < JumboPacketMin ? JumboPacketMin : jumboPacketConfiguration > JumboPacketMax ? JumboPacketMax : jumboPacketConfiguration); + context->config.vlanId = static_cast(vlanIdConfiguration <= 0xFFF ? vlanIdConfiguration : 0u); switch (flowControlConfiguration) { @@ -1339,6 +1354,7 @@ DevicePrepareHardware( } Write32(®s->Axi_Lpi_Entry_Interval, 15); // AutoAxiLpi after (interval + 1) * 64 clocks. Max value is 15. + auto busMode = Read32(®s->Dma_SysBus_Mode); busMode.EnableLpi = true; // true = allow LPI, honor AXI LPI request. busMode.UnlockOnPacket = false; // false = Wake for any received packet, true = only wake for magic packet. @@ -1348,7 +1364,6 @@ DevicePrepareHardware( busMode.AddressAlignedBeats = true; // Seemed to have fewer Rx FIFO overflows with this set to true. busMode.AutoAxiLpi = true; // true = enter LPI after (Axi_Lpi_Entry_Interval + 1) * 64 idle clocks. busMode.BurstLengths = context->config.blen; - busMode.FixedBurst = context->config.fixed_burst; Write32(®s->Dma_SysBus_Mode, busMode); diff --git a/drivers/net/dwc_eqos/device.h b/drivers/net/dwc_eqos/device.h index 36741da..5a168ac 100644 --- a/drivers/net/dwc_eqos/device.h +++ b/drivers/net/dwc_eqos/device.h @@ -20,6 +20,7 @@ struct DeviceConfig bool txFlowControl; // Adapter configuration (Ndi\params\*FlowControl). bool rxFlowControl; // Adapter configuration (Ndi\params\*FlowControl). UINT16 jumboFrame; // Adapter configuration (Ndi\params\*JumboFrame). 1514..9014. + UINT16 vlanId; // Adapter configuration (Ndi\params\*VlanID). 0..4095. UINT16 RxBufferSize() const { diff --git a/drivers/net/dwc_eqos/dwc_eqos.inf b/drivers/net/dwc_eqos/dwc_eqos.inf index 3c05612..9fb05d5 100644 --- a/drivers/net/dwc_eqos/dwc_eqos.inf +++ b/drivers/net/dwc_eqos/dwc_eqos.inf @@ -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\VlanID, ParamDesc, 0, %VlanID% +HKR, Ndi\params\VlanID, type, 0, "int" +HKR, Ndi\params\VlanID, default, 0, "0" +HKR, Ndi\params\VlanID, min, 0, "0" +HKR, Ndi\params\VlanID, max, 0, "4094" + HKR, Ndi\params\*JumboPacket, ParamDesc, 0, %JumboPacket% HKR, Ndi\params\*JumboPacket, type, 0, "int" HKR, Ndi\params\*JumboPacket, default, 0, "1514" @@ -203,6 +209,7 @@ RKCP = "Rockchip" DWCEQOS.DeviceDesc = "Synopsys DesignWare Ethernet Quality of Service (GMAC)" DWCEQOS.ServiceDesc = "DesignWare Ethernet" NetworkAddress = "Network Address" +VlanID = "VLAN ID" JumboPacket = "Jumbo Packet" FlowControl = "Flow Control" PriorityVlanTag = "Packet Priority & VLAN" diff --git a/drivers/net/dwc_eqos/registers.h b/drivers/net/dwc_eqos/registers.h index 3813b43..86c15b5 100644 --- a/drivers/net/dwc_eqos/registers.h +++ b/drivers/net/dwc_eqos/registers.h @@ -676,6 +676,25 @@ union MacVlanTagCtrl_t }; }; +union MacVlanIncl_t +{ + UINT32 Value32; + struct + { + UINT16 VlanTagTx; // VLT + + UINT8 VlanControl : 2; // VLC + UINT8 VlanControlPriority : 1; // VLP + UINT8 VlanS : 1; // CSVL + UINT8 VlanInput : 1; // VLTI + UINT8 VLanChannelInsertion : 1; + UINT8 Reserved22 : 2; + UINT8 Addr : 6; // ADDR + UINT8 ReadWriteControl : 1; // RDWR + UINT8 Busy : 1; // BUSY + }; +}; + union MacInterruptStatus_t { UINT32 Value32; @@ -995,7 +1014,7 @@ struct MacRegisters // The VLAN Tag Inclusion or Replacement register contains the VLAN tag for // insertion or replacement in the Transmit packets. It also contains the VLAN tag // insertion controls. - ULONG Mac_Vlan_Incl; + MacVlanIncl_t Mac_Vlan_Incl; // MAC_Inner_VLAN_Incl @ 0x0064 = 0x0: // The Inner VLAN Tag Inclusion or Replacement register contains the inner VLAN diff --git a/drivers/net/dwc_eqos/txqueue.cpp b/drivers/net/dwc_eqos/txqueue.cpp index 740a95b..ca9d2e2 100644 --- a/drivers/net/dwc_eqos/txqueue.cpp +++ b/drivers/net/dwc_eqos/txqueue.cpp @@ -23,6 +23,7 @@ struct TxQueueContext NET_EXTENSION packetChecksum; NET_EXTENSION fragmentLogical; UINT32 descCount; // A power of 2 between QueueDescriptorMinCount and QueueDescriptorMaxCount. + UINT16 vlanId; UINT8 txPbl; UINT16 lastMss; // MSS set by the most recent context descriptor. @@ -65,8 +66,8 @@ TxQueueStart(_In_ NETPACKETQUEUE queue) // PASSIVE_LEVEL, nonpaged (resume path) auto const context = TxQueueGetContext(queue); - context->lastMss = 0; // Make no assumptions about the device's current MSS. - context->lastVlanTag = 0; // Make no assumptions about the device's current vlan tag. + context->lastMss = 0xFFFF; // Make no assumptions about the device's current MSS. + context->lastVlanTag = 0; // Make no assumptions about the device's current vlan tag. context->descBegin = 0; context->descEnd = 0; @@ -211,11 +212,17 @@ TxQueueAdvance(_In_ NETPACKETQUEUE queue) NT_ASSERT(fragmentCount != 0); auto const ieee8021Q = *NetExtensionGetPacketIeee8021Q(&context->packetIeee8021Q, pktIndex); + UINT16 const ieee8021QPriority = (ieee8021Q.TxTagging & NetPacketTxIeee8021qActionFlagPriorityRequired) + ? ieee8021Q.PriorityCodePoint : 0u; + UINT16 const ieee8021QVlan = (ieee8021Q.TxTagging & NetPacketTxIeee8021qActionFlagVlanRequired) + ? ieee8021Q.VlanIdentifier : context->vlanId; + UINT16 const vlanTag = (ieee8021QPriority << 13) | ieee8021QVlan; + auto const vlanTagControl = vlanTag != 0 ? TxVlanTagControlInsert : TxVlanTagControlNone; + auto const contextTagNeeded = vlanTag != 0 && vlanTag != context->lastVlanTag; auto const gso = NetExtensionGetPacketGso(&context->packetGso, pktIndex); NT_ASSERT(gso->TCP.Mss <= 0x3FFF); // 14 bits auto const gsoMss = static_cast(gso->TCP.Mss); - auto const vlanTagControl = ieee8021Q.TxTagging != 0 ? TxVlanTagControlInsert : TxVlanTagControlNone; if (gsoMss != 0) // segmentation offload enabled { @@ -248,18 +255,6 @@ TxQueueAdvance(_In_ NETPACKETQUEUE queue) NT_ASSERT(headerLength <= packetLength); NT_ASSERT(userDescriptorsNeeded <= TxMaximumNumberOfFragments); - UINT16 newTag; - if (ieee8021Q.TxTagging != 0) - { - newTag = (ieee8021Q.PriorityCodePoint << 13) | ieee8021Q.VlanIdentifier; - NT_ASSERT(newTag != 0); - } - else - { - newTag = context->lastVlanTag; - } - - bool const contextTagNeeded = newTag != context->lastVlanTag; bool const contextMssNeeded = gsoMss != context->lastMss; bool const contextNeeded = contextTagNeeded || contextMssNeeded; @@ -275,7 +270,7 @@ TxQueueAdvance(_In_ NETPACKETQUEUE queue) { TxDescriptorContext descCtx = {}; descCtx.MaximumSegmentSize = gsoMss; - descCtx.VlanTag = newTag; + descCtx.VlanTag = vlanTag; descCtx.VlanTagValid = contextTagNeeded; descCtx.OneStepInputOrMssValid = true; descCtx.ContextType = true; @@ -289,7 +284,10 @@ TxQueueAdvance(_In_ NETPACKETQUEUE queue) context->descVirtual[descIndex].Context = descCtx; descIndex = (descIndex + 1) & descMask; context->lastMss = gsoMss; - context->lastVlanTag = newTag; + if (contextTagNeeded) + { + context->lastVlanTag = vlanTag; + } } auto const frag0LogicalAddress = NetExtensionGetFragmentLogicalAddress(&context->fragmentLogical, fragIndex)->LogicalAddress; @@ -365,25 +363,17 @@ TxQueueAdvance(_In_ NETPACKETQUEUE queue) : checksum.Layer3 ? TxChecksumInsertionEnabledHeaderOnly : TxChecksumInsertionDisabled; - if (ieee8021Q.TxTagging != 0) + // We might need a context descriptor. + if (fragmentCount + contextTagNeeded > EMPTY_DESC_REMAINING(descIndex)) { - UINT16 const newTag = (ieee8021Q.PriorityCodePoint << 13) | ieee8021Q.VlanIdentifier; - NT_ASSERT(newTag != 0); - if (newTag == context->lastVlanTag) - { - goto NoContextPacket; - } - - // We will need a context descriptor. - if (fragmentCount + 1u > EMPTY_DESC_REMAINING(descIndex)) - { - // Wait until more descriptors are free. - break; - } + // Wait until more descriptors are free. + break; + } + if (contextTagNeeded) + { TxDescriptorContext descCtx = {}; - descCtx.MaximumSegmentSize = context->lastMss; - descCtx.VlanTag = newTag; + descCtx.VlanTag = vlanTag; descCtx.VlanTagValid = true; descCtx.ContextType = true; descCtx.Own = true; @@ -395,17 +385,8 @@ TxQueueAdvance(_In_ NETPACKETQUEUE queue) NT_ASSERT(EMPTY_DESC_REMAINING(descIndex) != 0); context->descVirtual[descIndex].Context = descCtx; descIndex = (descIndex + 1) & descMask; - context->lastVlanTag = newTag; - } - else - { - NoContextPacket: - - if (fragmentCount > EMPTY_DESC_REMAINING(descIndex)) - { - // Wait until more descriptors are free. - break; - } + TraceWrite("TxTag", LEVEL_INFO, TraceLoggingHexInt16(vlanTag)); + context->lastVlanTag = vlanTag; } UINT32 frameLength = 0; @@ -635,6 +616,7 @@ TxQueueCreate( context->packetRing = NetRingCollectionGetPacketRing(rings); context->fragmentRing = NetRingCollectionGetFragmentRing(rings); context->descCount = QueueDescriptorCount(context->fragmentRing->NumberOfElements); + context->vlanId = deviceConfig.vlanId; context->txPbl = deviceConfig.txPbl; TraceWrite("TxQueueCreate-size", LEVEL_VERBOSE,