// ST - XENBUS_STORE_INTERFACE
// SU - XENBUS_SUSPEND_INTERFACE
-// REVISION C V ST SU
+// REVISION C V ST SU
#define DEFINE_REVISION_TABLE \
- DEFINE_REVISION(0x09000000, 1, 8, 2, 1), \
- DEFINE_REVISION(0x09000001, 2, 8, 2, 1), \
- DEFINE_REVISION(0x09000002, 2, 9, 2, 1)
+ DEFINE_REVISION(0x09000000, 1, 8, 2, 1), \
+ DEFINE_REVISION(0x09000001, 2, 8, 2, 1), \
+ DEFINE_REVISION(0x09000002, 2, 9, 2, 1), \
+ DEFINE_REVISION(0x09000003, 2, 10, 2, 1)
#endif // _REVISION_H
XENVIF_MAC_STATE_CHANGE
} XENVIF_VIF_CALLBACK_TYPE, *PXENVIF_VIF_CALLBACK_TYPE;
-/*! \typedef XENVIF_VIF_CALLBACK_PARAMETERS_V9
+union _XENVIF_VIF_CALLBACK_PARAMETERS_V9 {
+ struct {
+ PVOID Cookie;
+ PXENVIF_TRANSMITTER_PACKET_COMPLETION_INFO Completion;
+ } TransmitterReturnPacket;
+ struct {
+ ULONG Index;
+ PMDL Mdl;
+ ULONG Offset;
+ ULONG Length;
+ XENVIF_PACKET_CHECKSUM_FLAGS Flags;
+ USHORT MaximumSegmentSize;
+ USHORT TagControlInformation;
+ PXENVIF_PACKET_INFO Info;
+ PXENVIF_PACKET_HASH Hash;
+ BOOLEAN More;
+ PVOID Cookie;
+ } ReceiverQueuePacket;
+};
+
+/*! \typedef XENVIF_VIF_CALLBACK_PARAMETERS_V10
\brief VIF interface version 9 parameters for provider to subscriber callback function
\b XENVIF_TRANSMITTER_RETURN_PACKET:
\param Hash Hash information for the packet
\param More A flag to indicate whether more packets will be queued for the same CPU
\param Cookie Cookie that should be passed to XENVIF_RECEIVER_RETURN_PACKET method
+ \param Pause A flag to request that no more packets be queued for a short period of time
\b XENVIF_MAC_STATE_CHANGE:
No additional arguments
*/
-union _XENVIF_VIF_CALLBACK_PARAMETERS_V9 {
+union _XENVIF_VIF_CALLBACK_PARAMETERS_V10 {
struct {
PVOID Cookie;
PXENVIF_TRANSMITTER_PACKET_COMPLETION_INFO Completion;
PXENVIF_PACKET_HASH Hash;
BOOLEAN More;
PVOID Cookie;
+ BOOLEAN Pause;
} ReceiverQueuePacket;
};
...
);
-typedef union _XENVIF_VIF_CALLBACK_PARAMETERS_V9 XENVIF_VIF_CALLBACK_PARAMETERS, *PXENVIF_VIF_CALLBACK_PARAMETERS;
+typedef VOID
+(*XENVIF_VIF_CALLBACK_V9)(
+ IN PVOID Argument OPTIONAL,
+ IN XENVIF_VIF_CALLBACK_TYPE Type,
+ IN union _XENVIF_VIF_CALLBACK_PARAMETERS_V9 *Parameters
+ );
+
+typedef union _XENVIF_VIF_CALLBACK_PARAMETERS_V10 XENVIF_VIF_CALLBACK_PARAMETERS, *PXENVIF_VIF_CALLBACK_PARAMETERS;
/*! \typedef XENVIF_VIF_CALLBACK
\brief Provider to subscriber callback function
IN PVOID Argument OPTIONAL
);
+typedef NTSTATUS
+(*XENVIF_VIF_ENABLE_V9)(
+ IN PINTERFACE Interface,
+ IN XENVIF_VIF_CALLBACK_V9 Callback,
+ IN PVOID Argument OPTIONAL
+ );
+
/*! \typedef XENVIF_VIF_ENABLE
\brief Enable the VIF interface
\ingroup interfaces
*/
struct _XENVIF_VIF_INTERFACE_V9 {
+ INTERFACE Interface;
+ XENVIF_VIF_ACQUIRE Acquire;
+ XENVIF_VIF_RELEASE Release;
+ XENVIF_VIF_ENABLE_V9 EnableVersion9;
+ XENVIF_VIF_DISABLE Disable;
+ XENVIF_VIF_QUERY_STATISTIC QueryStatistic;
+ XENVIF_VIF_QUERY_RING_COUNT QueryRingCount;
+ XENVIF_VIF_UPDATE_HASH_MAPPING UpdateHashMapping;
+ XENVIF_VIF_RECEIVER_RETURN_PACKET ReceiverReturnPacket;
+ XENVIF_VIF_RECEIVER_SET_OFFLOAD_OPTIONS ReceiverSetOffloadOptions;
+ XENVIF_VIF_RECEIVER_SET_BACKFILL_SIZE ReceiverSetBackfillSize;
+ XENVIF_VIF_RECEIVER_QUERY_RING_SIZE ReceiverQueryRingSize;
+ XENVIF_VIF_RECEIVER_SET_HASH_ALGORITHM ReceiverSetHashAlgorithm;
+ XENVIF_VIF_RECEIVER_QUERY_HASH_CAPABILITIES ReceiverQueryHashCapabilities;
+ XENVIF_VIF_RECEIVER_UPDATE_HASH_PARAMETERS ReceiverUpdateHashParameters;
+ XENVIF_VIF_TRANSMITTER_QUEUE_PACKET TransmitterQueuePacket;
+ XENVIF_VIF_TRANSMITTER_QUERY_OFFLOAD_OPTIONS TransmitterQueryOffloadOptions;
+ XENVIF_VIF_TRANSMITTER_QUERY_LARGE_PACKET_SIZE TransmitterQueryLargePacketSize;
+ XENVIF_VIF_TRANSMITTER_QUERY_RING_SIZE TransmitterQueryRingSize;
+ XENVIF_VIF_MAC_QUERY_STATE MacQueryState;
+ XENVIF_VIF_MAC_QUERY_MAXIMUM_FRAME_SIZE MacQueryMaximumFrameSize;
+ XENVIF_VIF_MAC_QUERY_PERMANENT_ADDRESS MacQueryPermanentAddress;
+ XENVIF_VIF_MAC_QUERY_CURRENT_ADDRESS MacQueryCurrentAddress;
+ XENVIF_VIF_MAC_QUERY_MULTICAST_ADDRESSES MacQueryMulticastAddresses;
+ XENVIF_VIF_MAC_SET_MULTICAST_ADDRESSES MacSetMulticastAddresses;
+ XENVIF_VIF_MAC_SET_FILTER_LEVEL MacSetFilterLevel;
+ XENVIF_VIF_MAC_QUERY_FILTER_LEVEL MacQueryFilterLevel;
+};
+
+/*! \struct _XENVIF_VIF_INTERFACE_V10
+ \brief VIF interface version 10
+ \ingroup interfaces
+*/
+struct _XENVIF_VIF_INTERFACE_V10 {
INTERFACE Interface;
XENVIF_VIF_ACQUIRE Acquire;
XENVIF_VIF_RELEASE Release;
XENVIF_VIF_MAC_QUERY_FILTER_LEVEL MacQueryFilterLevel;
};
-typedef struct _XENVIF_VIF_INTERFACE_V9 XENVIF_VIF_INTERFACE, *PXENVIF_VIF_INTERFACE;
+typedef struct _XENVIF_VIF_INTERFACE_V10 XENVIF_VIF_INTERFACE, *PXENVIF_VIF_INTERFACE;
/*! \def XENVIF_VIF
\brief Macro at assist in method invocation
#endif // _WINDLL
#define XENVIF_VIF_INTERFACE_VERSION_MIN 8
-#define XENVIF_VIF_INTERFACE_VERSION_MAX 9
+#define XENVIF_VIF_INTERFACE_VERSION_MAX 10
#endif // _XENVIF_INTERFACE_H
PROCESSOR_NUMBER TargetProcessor;
LIST_ENTRY PacketComplete;
XENVIF_RECEIVER_HASH Hash;
+ BOOLEAN Paused;
+ BOOLEAN Flush;
} XENVIF_RECEIVER_RING, *PXENVIF_RECEIVER_RING;
typedef struct _XENVIF_RECEIVER_PACKET {
PXENVIF_VIF_CONTEXT Context;
LIST_ENTRY List;
PLIST_ENTRY ListEntry;
+ BOOLEAN Pause;
Receiver = Ring->Receiver;
Frontend = Receiver->Frontend;
InitializeListHead(&List);
- ListEntry = InterlockedExchangePointer(&Ring->PacketQueue, NULL);
+ KeMemoryBarrier();
- // Packets are held in the queue in reverse order so that the most
- // recent is always head of the list. This is necessary to allow
- // addition to the list to be done atomically.
+ // Only process the PacketQueue if the ring is not paused or it is being flushed
+ if (!Ring->Paused || Ring->Flush) {
+ ListEntry = InterlockedExchangePointer(&Ring->PacketQueue, NULL);
- while (ListEntry != NULL) {
- PLIST_ENTRY NextEntry;
+ // Packets are held in the queue in reverse order so that the most
+ // recent is always head of the list. This is necessary to allow
+ // addition to the list to be done atomically.
- NextEntry = ListEntry->Blink;
- ListEntry->Flink = ListEntry->Blink = ListEntry;
+ while (ListEntry != NULL) {
+ PLIST_ENTRY NextEntry;
- InsertHeadList(&List, ListEntry);
+ NextEntry = ListEntry->Blink;
+ ListEntry->Flink = ListEntry->Blink = ListEntry;
- ListEntry = NextEntry;
- }
+ InsertHeadList(&List, ListEntry);
- while (!IsListEmpty(&List)) {
- PXENVIF_RECEIVER_PACKET Packet;
+ ListEntry = NextEntry;
+ }
- ListEntry = RemoveHeadList(&List);
- ASSERT3P(ListEntry, !=, &List);
+ while (!IsListEmpty(&List)) {
+ PXENVIF_RECEIVER_PACKET Packet;
- RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+ ListEntry = RemoveHeadList(&List);
+ ASSERT3P(ListEntry, !=, &List);
- Packet = CONTAINING_RECORD(ListEntry, XENVIF_RECEIVER_PACKET, ListEntry);
- ReceiverRingProcessPacket(Ring, Packet);
+ RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+
+ Packet = CONTAINING_RECORD(ListEntry, XENVIF_RECEIVER_PACKET, ListEntry);
+ ReceiverRingProcessPacket(Ring, Packet);
+ }
}
- while (!IsListEmpty(&Ring->PacketComplete)) {
+ Pause = FALSE;
+ while (!IsListEmpty(&Ring->PacketComplete) && !Pause) {
PXENVIF_RECEIVER_PACKET Packet;
PXENVIF_PACKET_INFO Info;
PUCHAR BaseVa;
&Packet->Info,
&Packet->Hash,
!IsListEmpty(&Ring->PacketComplete) ? TRUE : FALSE,
- Packet);
+ Packet,
+ &Pause);
+
+ // If we are flushing then we can't pause
+ if (Ring->Flush)
+ Pause = FALSE;
+ }
+
+ if (Pause) {
+ Ring->Paused = TRUE;
+
+ if (KeInsertQueueDpc(&Ring->QueueDpc, NULL, NULL))
+ Ring->QueueDpcs++;
+ } else {
+ BOOLEAN Paused = Ring->Paused;
+
+ Ring->Paused = FALSE;
+
+ // PollDpc is cleared before Flush is set
+ if (Paused && !Ring->Flush && KeInsertQueueDpc(&Ring->PollDpc, NULL, NULL))
+ Ring->PollDpcs++;
}
}
Count = 0;
- if (!Ring->Enabled)
+ if (!Ring->Enabled || Ring->Paused)
goto done;
for (;;) {
RtlZeroMemory(&Ring->TargetProcessor, sizeof (PROCESSOR_NUMBER));
+ Ring->Flush = TRUE;
+ KeMemoryBarrier();
+
+ KeInsertQueueDpc(&Ring->QueueDpc, NULL, NULL);
KeFlushQueuedDpcs();
+ Ring->Flush = FALSE;
+
RtlZeroMemory(&Ring->QueueDpc, sizeof (KDPC));
ThreadAlert(Ring->WatchdogThread);
PVOID Argument;
XENVIF_VIF_CALLBACK_V8 CallbackVersion8;
PVOID ArgumentVersion8;
+ XENVIF_VIF_CALLBACK_V9 CallbackVersion9;
+ PVOID ArgumentVersion9;
+ LONG Queued;
PXENVIF_THREAD MacThread;
KEVENT MacEvent;
XENBUS_SUSPEND_INTERFACE SuspendInterface;
static VOID
VifCallbackVersion8(
- IN PVOID _Argument OPTIONAL,
- IN XENVIF_VIF_CALLBACK_TYPE Type,
- IN PXENVIF_VIF_CALLBACK_PARAMETERS Parameters
+ IN PVOID _Argument OPTIONAL,
+ IN XENVIF_VIF_CALLBACK_TYPE Type,
+ IN union _XENVIF_VIF_CALLBACK_PARAMETERS_V9 *Parameters
)
{
- PXENVIF_VIF_CONTEXT Context = _Argument;
- XENVIF_VIF_CALLBACK_V8 Callback = Context->CallbackVersion8;
- PVOID Argument = Context->ArgumentVersion8;
+ PXENVIF_VIF_CONTEXT Context = _Argument;
+ XENVIF_VIF_CALLBACK_V8 Callback = Context->CallbackVersion8;
+ PVOID Argument = Context->ArgumentVersion8;
switch (Type) {
case XENVIF_TRANSMITTER_RETURN_PACKET: {
}
}
+static VOID
+VifCallbackVersion9(
+ IN PVOID _Argument OPTIONAL,
+ IN XENVIF_VIF_CALLBACK_TYPE Type,
+ IN PXENVIF_VIF_CALLBACK_PARAMETERS Parameters
+ )
+{
+#define XENVIF_RECEIVER_QUEUE_MAX 1024 // Chosen to match IN_NDIS_MAX in XENNET
+
+ PXENVIF_VIF_CONTEXT Context = _Argument;
+ XENVIF_VIF_CALLBACK_V9 Callback = Context->CallbackVersion9;
+ PVOID Argument = Context->ArgumentVersion9;
+ union _XENVIF_VIF_CALLBACK_PARAMETERS_V9 ParametersVersion9;
+
+ switch (Type) {
+ case XENVIF_TRANSMITTER_RETURN_PACKET:
+ ParametersVersion9.TransmitterReturnPacket.Cookie = Parameters->TransmitterReturnPacket.Cookie;
+ ParametersVersion9.TransmitterReturnPacket.Completion = Parameters->TransmitterReturnPacket.Completion;
+ break;
+
+ case XENVIF_RECEIVER_QUEUE_PACKET:
+ ParametersVersion9.ReceiverQueuePacket.Index = Parameters->ReceiverQueuePacket.Index;
+ ParametersVersion9.ReceiverQueuePacket.Mdl = Parameters->ReceiverQueuePacket.Mdl;
+ ParametersVersion9.ReceiverQueuePacket.Offset = Parameters->ReceiverQueuePacket.Offset;
+ ParametersVersion9.ReceiverQueuePacket.Length = Parameters->ReceiverQueuePacket.Length;
+ ParametersVersion9.ReceiverQueuePacket.Flags = Parameters->ReceiverQueuePacket.Flags;
+ ParametersVersion9.ReceiverQueuePacket.MaximumSegmentSize = Parameters->ReceiverQueuePacket.MaximumSegmentSize;
+ ParametersVersion9.ReceiverQueuePacket.TagControlInformation = Parameters->ReceiverQueuePacket.TagControlInformation;
+ ParametersVersion9.ReceiverQueuePacket.Info = Parameters->ReceiverQueuePacket.Info;
+ ParametersVersion9.ReceiverQueuePacket.Hash = Parameters->ReceiverQueuePacket.Hash;
+ ParametersVersion9.ReceiverQueuePacket.More = Parameters->ReceiverQueuePacket.More;
+ ParametersVersion9.ReceiverQueuePacket.Cookie = Parameters->ReceiverQueuePacket.Cookie;
+ break;
+
+ case XENVIF_MAC_STATE_CHANGE:
+ // No parameters to translate
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ Callback(Argument, Type, &ParametersVersion9);
+
+ switch (Type) {
+ case XENVIF_TRANSMITTER_RETURN_PACKET:
+ break;
+
+ case XENVIF_RECEIVER_QUEUE_PACKET: {
+ LONG Queued;
+
+ Queued = (Parameters->ReceiverQueuePacket.More) ?
+ InterlockedIncrement(&Context->Queued) :
+ InterlockedExchange(&Context->Queued, 0);
+
+ //
+ // Once the limit is hit XENNET will have started indicating 'low resources' to NDIS so we
+ // should pause any further attempts to queue received packets.
+ //
+ if (Queued > XENVIF_RECEIVER_QUEUE_MAX) {
+ Parameters->ReceiverQueuePacket.Pause = TRUE;
+ (VOID) InterlockedExchange(&Context->Queued, 0);
+ } else {
+ Parameters->ReceiverQueuePacket.Pause = FALSE;
+ }
+ break;
+ }
+ case XENVIF_MAC_STATE_CHANGE:
+ // No parameters to translate
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+#undef XENVIF_RECEIVER_QUEUE_MAX
+}
+
+static NTSTATUS
+VifEnableVersion9(
+ IN PINTERFACE Interface,
+ IN XENVIF_VIF_CALLBACK_V9 Callback,
+ IN PVOID Argument
+ )
+{
+ PXENVIF_VIF_CONTEXT Context = Interface->Context;
+ KIRQL Irql;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ AcquireMrswLockExclusive(&Context->Lock, &Irql);
+
+ Context->CallbackVersion9 = Callback;
+ Context->ArgumentVersion9 = Argument;
+
+ ReleaseMrswLockExclusive(&Context->Lock, Irql, FALSE);
+
+ status = VifEnable(Interface, VifCallbackVersion9, Context);
+
+ Trace("<====\n");
+
+ return status;
+}
+
static NTSTATUS
VifEnableVersion8(
IN PINTERFACE Interface,
ReleaseMrswLockExclusive(&Context->Lock, Irql, FALSE);
- status = VifEnable(Interface, VifCallbackVersion8, Context);
+ status = VifEnableVersion9(Interface, VifCallbackVersion8, Context);
Trace("<====\n");
Context->ArgumentVersion8 = NULL;
Context->CallbackVersion8 = NULL;
+ Context->ArgumentVersion9 = NULL;
+ Context->CallbackVersion9 = NULL;
+
ReleaseMrswLockShared(&Context->Lock);
done:
{ sizeof (struct _XENVIF_VIF_INTERFACE_V9), 9, NULL, NULL, NULL },
VifAcquire,
VifRelease,
+ VifEnableVersion9,
+ VifDisable,
+ VifQueryStatistic,
+ VifQueryRingCount,
+ VifUpdateHashMapping,
+ VifReceiverReturnPacket,
+ VifReceiverSetOffloadOptions,
+ VifReceiverSetBackfillSize,
+ VifReceiverQueryRingSize,
+ VifReceiverSetHashAlgorithm,
+ VifReceiverQueryHashCapabilities,
+ VifReceiverUpdateHashParameters,
+ VifTransmitterQueuePacket,
+ VifTransmitterQueryOffloadOptions,
+ VifTransmitterQueryLargePacketSize,
+ VifTransmitterQueryRingSize,
+ VifMacQueryState,
+ VifMacQueryMaximumFrameSize,
+ VifMacQueryPermanentAddress,
+ VifMacQueryCurrentAddress,
+ VifMacQueryMulticastAddresses,
+ VifMacSetMulticastAddresses,
+ VifMacSetFilterLevel,
+ VifMacQueryFilterLevel
+};
+
+static struct _XENVIF_VIF_INTERFACE_V10 VifInterfaceVersion10 = {
+ { sizeof (struct _XENVIF_VIF_INTERFACE_V10), 10, NULL, NULL, NULL },
+ VifAcquire,
+ VifRelease,
VifEnable,
VifDisable,
VifQueryStatistic,
status = STATUS_SUCCESS;
break;
}
+ case 10: {
+ struct _XENVIF_VIF_INTERFACE_V10 *VifInterface;
+
+ VifInterface = (struct _XENVIF_VIF_INTERFACE_V10 *)Interface;
+
+ status = STATUS_BUFFER_OVERFLOW;
+ if (Size < sizeof (struct _XENVIF_VIF_INTERFACE_V10))
+ break;
+
+ *VifInterface = VifInterfaceVersion10;
+
+ ASSERT3U(Interface->Version, ==, Version);
+ Interface->Context = Context;
+
+ status = STATUS_SUCCESS;
+ break;
+ }
default:
status = STATUS_NOT_SUPPORTED;
break;
{
Trace("====>\n");
+ Context->Queued = 0;
+
Context->Pdo = NULL;
Context->Version = 0;
IN PXENVIF_PACKET_INFO Info,
IN PXENVIF_PACKET_HASH Hash,
IN BOOLEAN More,
- IN PVOID Cookie
+ IN PVOID Cookie,
+ OUT PBOOLEAN Pause
)
{
KIRQL Irql;
Context->Callback(Context->Argument, XENVIF_RECEIVER_QUEUE_PACKET, &Parameters);
+ *Pause = Parameters.ReceiverQueuePacket.Pause;
+
KeLowerIrql(Irql);
}
IN PXENVIF_PACKET_INFO Info,
IN PXENVIF_PACKET_HASH Hash,
IN BOOLEAN More,
- IN PVOID Cookie
+ IN PVOID Cookie,
+ OUT PBOOLEAN Pause
);
extern VOID