summaryrefslogtreecommitdiff
path: root/network/netadaptercx/netvadapterlibrary/code/rxqueue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'network/netadaptercx/netvadapterlibrary/code/rxqueue.cpp')
-rw-r--r--network/netadaptercx/netvadapterlibrary/code/rxqueue.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/network/netadaptercx/netvadapterlibrary/code/rxqueue.cpp b/network/netadaptercx/netvadapterlibrary/code/rxqueue.cpp
new file mode 100644
index 00000000..6eed638c
--- /dev/null
+++ b/network/netadaptercx/netvadapterlibrary/code/rxqueue.cpp
@@ -0,0 +1,156 @@
+// Copyright (c) Microsoft Corporation. All rights reserved
+
+#include "pch.hpp"
+#include "netvadapter.h"
+#include "rxqueue.h"
+#include "memory.h"
+
+static
+void
+CheckForWakeFrame(
+ NetvRxQueue * rx
+)
+{
+ NET_RING_FRAGMENT_ITERATOR fi = NetRingGetAllFragments(rx->m_rings);
+
+ if (! NetFragmentIteratorHasAny(&fi))
+ {
+ return;
+ }
+
+ auto *fragment = NetFragmentIteratorGetFragment(&fi);
+ auto *rxVirtualAddress = NetExtensionGetFragmentVirtualAddress(
+ &rx->VirtualAddressExtension,
+ NetFragmentIteratorGetIndex(&fi));
+
+ auto *fragmentBuffer = reinterpret_cast<unsigned char *>(rxVirtualAddress->VirtualAddress) + fragment->Offset;
+
+ fragment->ValidLength = EnlCopyWakeFrame(
+ NetvEnlMLink[rx->m_adapter.EnlIndex].LinkHandle[0],
+ fragmentBuffer,
+ fragment->Capacity);
+
+ // If there was a pending wake frame mark this fragment as complete, the normal advance code will get to it
+ fragment->Scratch = fragment->ValidLength > 0 ? 1 : 0;
+
+ rx->CheckedWakeFrame = true;
+}
+
+
+NetvRxQueue::NetvRxQueue(
+ NETPACKETQUEUE Handle,
+ NetvAdapter & Adapter
+)
+ : NetvQueue{Handle, Adapter, NetRxQueueGetRingCollection(Handle)}
+{
+ NET_EXTENSION_QUERY extension;
+
+ NET_EXTENSION_QUERY_INIT(
+ &extension,
+ NET_FRAGMENT_EXTENSION_VIRTUAL_ADDRESS_NAME,
+ NET_FRAGMENT_EXTENSION_VIRTUAL_ADDRESS_VERSION_1,
+ NetExtensionTypeFragment);
+
+ NetRxQueueGetExtension(m_handle, &extension, &VirtualAddressExtension);
+
+ NET_EXTENSION_QUERY_INIT(
+ &extension,
+ NET_PACKET_EXTENSION_RSC_NAME,
+ NET_PACKET_EXTENSION_RSC_VERSION_2,
+ NetExtensionTypePacket);
+
+ NetRxQueueGetExtension(m_handle, &extension, &UdpRscExtension);
+
+ NET_EXTENSION_QUERY_INIT(
+ &extension,
+ NET_PACKET_EXTENSION_CHECKSUM_NAME,
+ NET_PACKET_EXTENSION_CHECKSUM_VERSION_1,
+ NetExtensionTypePacket);
+
+ NetRxQueueGetExtension(m_handle, &extension, &RxXSumExtension);
+
+ EnlQueueHandle = EnlCreateQueue(Handle, RX);
+}
+
+_Use_decl_annotations_
+void
+NetvRxQueue::Destroy(
+ void
+)
+{
+ EnlDestroyQueue(EnlQueueHandle, RX);
+}
+
+void
+NetvRxQueue::Start(
+ void
+)
+{
+ auto link = NetvEnlMLink[m_adapter.EnlIndex].LinkHandle[0];
+ auto port = &link->Ports[m_adapter.EnlPortIndex];
+ auto queue = &port->RxQueue[0];
+
+ WDFVERIFY(queue->State == Stopped);
+
+ queue->QueueNext = queue->QueueEnd = 0U;
+
+ EnlIndicateQueueState(EnlQueueHandle, Started);
+}
+
+void
+NetvRxQueue::Stop(
+ void
+)
+{
+ EnlIndicateQueueState(EnlQueueHandle, Stopped);
+}
+
+_Use_decl_annotations_
+void
+NetvRxQueue::Advance(
+ void
+)
+{
+ auto fr = GetFragmentRing();
+ NET_RING_PACKET_ITERATOR pi = NetRingGetAllPackets(m_rings);
+ NET_RING_FRAGMENT_ITERATOR fi = NetRingGetAllFragments(m_rings);
+
+ // Ideally this would run in EvtQueueStart, but at that point the receive buffers are not
+ // attached to the fragment yet
+ if (! CheckedWakeFrame)
+ {
+ CheckForWakeFrame(this);
+ }
+
+ // Move begin index forward for all fragments with Scratch == 1, thus returning them to the OS since we're done processing them.
+ for (; NetFragmentIteratorHasAny(&fi) && NetPacketIteratorHasAny(&pi); NetPacketIteratorAdvance(&pi), NetFragmentIteratorAdvance(&fi))
+ {
+ NET_FRAGMENT const * fragment = NetFragmentIteratorGetFragment(&fi);
+ if (! fragment->Scratch)
+ {
+ break;
+ }
+ }
+
+ NetFragmentIteratorSet(&fi);
+ NetPacketIteratorSet(&pi);
+ EnlRingDoorBell(EnlQueueHandle, fr->EndIndex);
+}
+
+_Use_decl_annotations_
+void
+NetvRxQueue::Cancel(
+ void
+)
+{
+ CancelRxPackets(m_rings);
+}
+
+_Use_decl_annotations_
+void
+NetvRxQueue::SetNotify(
+ bool NotificationEnabled
+)
+{
+ EnlArmInterrupt(EnlQueueHandle, NotificationEnabled);
+}