[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[win-pv-devel] [PATCH 2/3] Move the Receiver and Transmitter event and DPC processing...



...into the new Poller sub-system.

For efficiency it is desirable to have a single DPC handle both Receiver
and Transmitter polling, even if there are separate event channels for
the shared rings.

This patch moves all the basic event and DPC code into the Poller
subsystem, which calls back into the Transmitter and Receiver sub-systems
(to poll the shared rings) from its single per-CPU DPC.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 src/xenvif/frontend.c    |   48 --
 src/xenvif/frontend.h    |   10 -
 src/xenvif/poller.c      | 1322 +++++++++++++++++++++++++++++++++++++++++++++-
 src/xenvif/poller.h      |   24 +-
 src/xenvif/receiver.c    |  393 +++-----------
 src/xenvif/receiver.h    |    6 +
 src/xenvif/transmitter.c |  381 ++-----------
 src/xenvif/transmitter.h |    6 +
 8 files changed, 1449 insertions(+), 741 deletions(-)

diff --git a/src/xenvif/frontend.c b/src/xenvif/frontend.c
index f715c19..9949357 100644
--- a/src/xenvif/frontend.c
+++ b/src/xenvif/frontend.c
@@ -81,7 +81,6 @@ struct _XENVIF_FRONTEND {
     USHORT                      BackendDomain;
     ULONG                       MaxQueues;
     ULONG                       NumQueues;
-    BOOLEAN                     Split;
     ULONG                       DisableToeplitz;
 
     PXENVIF_MAC                 Mac;
@@ -1800,50 +1799,6 @@ FrontendGetNumQueues(
     return __FrontendGetNumQueues(Frontend);
 }
 
-static VOID
-FrontendSetSplit(
-    IN  PXENVIF_FRONTEND    Frontend
-    )
-{
-    PCHAR                   Buffer;
-    NTSTATUS                status;
-
-    status = XENBUS_STORE(Read,
-                          &Frontend->StoreInterface,
-                          NULL,
-                          __FrontendGetBackendPath(Frontend),
-                          "feature-split-event-channels",
-                          &Buffer);
-    if (NT_SUCCESS(status)) {
-        Frontend->Split = (BOOLEAN)strtol(Buffer, NULL, 2);
-
-        XENBUS_STORE(Free,
-                     &Frontend->StoreInterface,
-                     Buffer);
-    } else {
-        Frontend->Split = FALSE;
-    }
-
-    Info("%s: %s\n", __FrontendGetPath(Frontend),
-         (Frontend->Split) ? "TRUE" : "FALSE");
-}
-
-static FORCEINLINE BOOLEAN
-__FrontendIsSplit(
-    IN  PXENVIF_FRONTEND    Frontend
-    )
-{
-    return Frontend->Split;
-}
-
-BOOLEAN
-FrontendIsSplit(
-    IN  PXENVIF_FRONTEND    Frontend
-    )
-{
-    return __FrontendIsSplit(Frontend);
-}
-
 static FORCEINLINE NTSTATUS
 __FrontendUpdateHash(
     PXENVIF_FRONTEND        Frontend,
@@ -2208,7 +2163,6 @@ FrontendConnect(
         goto fail3;
 
     FrontendSetNumQueues(Frontend);
-    FrontendSetSplit(Frontend);
 
     status = PollerConnect(__FrontendGetPoller(Frontend));
     if (!NT_SUCCESS(status))
@@ -2360,7 +2314,6 @@ fail4:
 
     MacDisconnect(__FrontendGetMac(Frontend));
 
-    Frontend->Split = FALSE;
     Frontend->NumQueues = 0;
 
 fail3:
@@ -2398,7 +2351,6 @@ FrontendDisconnect(
     PollerDisconnect(__FrontendGetPoller(Frontend));
     MacDisconnect(__FrontendGetMac(Frontend));
 
-    Frontend->Split = FALSE;
     Frontend->NumQueues = 0;
 
     XENBUS_DEBUG(Deregister,
diff --git a/src/xenvif/frontend.h b/src/xenvif/frontend.h
index 92008d0..7f3b7c5 100644
--- a/src/xenvif/frontend.h
+++ b/src/xenvif/frontend.h
@@ -123,16 +123,6 @@ FrontendGetNumQueues(
     IN  PXENVIF_FRONTEND    Frontend
     );
 
-extern BOOLEAN
-FrontendIsSplit(
-    IN  PXENVIF_FRONTEND    Frontend
-    );
-
-extern BOOLEAN
-FrontendIsSplit(
-    IN  PXENVIF_FRONTEND    Frontend
-    );
-
 extern PCHAR
 FrontendFormatPath(
     IN  PXENVIF_FRONTEND    Frontend,
diff --git a/src/xenvif/poller.c b/src/xenvif/poller.c
index 4ac358e..7b60022 100644
--- a/src/xenvif/poller.c
+++ b/src/xenvif/poller.c
@@ -42,6 +42,8 @@
 
 #include "pdo.h"
 #include "frontend.h"
+#include "transmitter.h"
+#include "receiver.h"
 #include "poller.h"
 #include "vif.h"
 #include "thread.h"
@@ -52,38 +54,1013 @@
 
 #define MAXNAMELEN  128
 
+typedef struct _XENVIF_POLLER_INSTANCE XENVIF_POLLER_INSTANCE, 
*PXENVIF_POLLER_INSTANCE;
+
+typedef enum _XENVIF_POLLER_CHANNEL_TYPE {
+    XENVIF_POLLER_CHANNEL_RECEIVER,
+    XENVIF_POLLER_CHANNEL_TRANSMITTER,
+    XENVIF_POLLER_CHANNEL_COMBINED,
+    XENVIF_POLLER_CHANNEL_TYPE_COUNT
+} XENVIF_POLLER_CHANNEL_TYPE, *PXENVIF_POLLER_CHANNEL_TYPE;
+
+#define XENVIF_POLLER_CHANNEL_INVALID XENVIF_POLLER_CHANNEL_TYPE_COUNT
+
+typedef struct _XENVIF_POLLER_CHANNEL {
+    PXENVIF_POLLER_INSTANCE     Instance;
+    XENVIF_POLLER_CHANNEL_TYPE  Type;
+    const CHAR                  *Node;
+    PXENBUS_EVTCHN_CHANNEL      Channel;
+    ULONG                       Events;
+} XENVIF_POLLER_CHANNEL, *PXENVIF_POLLER_CHANNEL;
+
+struct _XENVIF_POLLER_INSTANCE {
+    PXENVIF_POLLER          Poller;
+    ULONG                   Index;
+    PCHAR                   Path;
+    KSPIN_LOCK              Lock;
+    KDPC                    Dpc;
+    ULONG                   Dpcs;
+    KTIMER                  Timer;
+    KDPC                    TimerDpc;
+    PXENVIF_POLLER_CHANNEL  Channel[XENVIF_POLLER_CHANNEL_TYPE_COUNT];
+    BOOLEAN                 Enabled;
+    LONG                    Pending;
+};
+
 struct _XENVIF_POLLER {
     PXENVIF_FRONTEND        Frontend;
+    PXENVIF_POLLER_INSTANCE *Instance;
+    BOOLEAN                 Split;
+    XENBUS_STORE_INTERFACE  StoreInterface;
+    XENBUS_EVTCHN_INTERFACE EvtchnInterface;
     XENBUS_DEBUG_INTERFACE  DebugInterface;
     PXENBUS_DEBUG_CALLBACK  DebugCallback;
 };
 
-#define XENVIF_POLLER_TAG  'LLOP'
+#define XENVIF_POLLER_TAG  'LLOP'
+
+static FORCEINLINE PVOID
+__PollerAllocate(
+    IN  ULONG   Length
+    )
+{
+    return __AllocatePoolWithTag(NonPagedPool, Length, XENVIF_POLLER_TAG);
+}
+
+static FORCEINLINE VOID
+__PollerFree(
+    IN  PVOID   Buffer
+    )
+{
+    __FreePoolWithTag(Buffer, XENVIF_POLLER_TAG);
+}
+
+static NTSTATUS
+PollerChannelInitialize(
+    IN  PXENVIF_POLLER_INSTANCE Instance,
+    IN  ULONG                   Type,
+    OUT PXENVIF_POLLER_CHANNEL  *Channel
+    )
+{
+    NTSTATUS                    status;
+
+    *Channel = __PollerAllocate(sizeof (XENVIF_POLLER_CHANNEL));
+
+    status = STATUS_NO_MEMORY;
+    if (*Channel == NULL)
+        goto fail1;
+
+    (*Channel)->Instance = Instance;
+    (*Channel)->Type = Type;
+
+    switch (Type) {
+    case XENVIF_POLLER_CHANNEL_RECEIVER:
+        (*Channel)->Node = "event-channel-rx";
+        break;
+
+    case XENVIF_POLLER_CHANNEL_TRANSMITTER:
+        (*Channel)->Node = "event-channel-tx";
+        break;
+
+    case XENVIF_POLLER_CHANNEL_COMBINED:
+        (*Channel)->Node = "event-channel";
+        break;
+
+    default:
+        ASSERT(FALSE);
+        break;
+    }
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static VOID
+PollerChannelSetPending(
+    IN  PXENVIF_POLLER_CHANNEL  Channel
+    )
+{
+    PXENVIF_POLLER_INSTANCE     Instance;
+
+    Instance = Channel->Instance;
+
+    switch (Channel->Type)
+    {
+    case XENVIF_POLLER_CHANNEL_RECEIVER:
+        (VOID) InterlockedBitTestAndSet(&Instance->Pending,
+                                        XENVIF_POLLER_EVENT_RECEIVE);
+        break;
+
+    case XENVIF_POLLER_CHANNEL_TRANSMITTER:
+        (VOID) InterlockedBitTestAndSet(&Instance->Pending,
+                                        XENVIF_POLLER_EVENT_TRANSMIT);
+        break;
+
+    case XENVIF_POLLER_CHANNEL_COMBINED:
+        (VOID) InterlockedBitTestAndSet(&Instance->Pending,
+                                        XENVIF_POLLER_EVENT_RECEIVE);
+        (VOID) InterlockedBitTestAndSet(&Instance->Pending,
+                                        XENVIF_POLLER_EVENT_TRANSMIT);
+        break;
+
+    default:
+        ASSERT(FALSE);
+        break;
+    }
+}
+
+static FORCEINLINE BOOLEAN
+__BitTest(
+    IN  PLONG   Mask,
+    IN  LONG    Bit
+    )
+{
+    return (*Mask & (1L << Bit)) ? TRUE : FALSE;
+}
+
+static BOOLEAN
+PollerChannelTestPending(
+    IN  PXENVIF_POLLER_CHANNEL  Channel
+    )
+{
+    PXENVIF_POLLER_INSTANCE     Instance;
+
+    Instance = Channel->Instance;
+
+    switch (Channel->Type)
+    {
+    case XENVIF_POLLER_CHANNEL_RECEIVER:
+        if (__BitTest(&Instance->Pending, XENVIF_POLLER_EVENT_RECEIVE))
+            return TRUE;
+
+        break;
+
+    case XENVIF_POLLER_CHANNEL_TRANSMITTER:
+        if (__BitTest(&Instance->Pending, XENVIF_POLLER_EVENT_TRANSMIT))
+            return TRUE;
+
+        break;
+
+    case XENVIF_POLLER_CHANNEL_COMBINED:
+        if (__BitTest(&Instance->Pending, XENVIF_POLLER_EVENT_RECEIVE) ||
+            __BitTest(&Instance->Pending, XENVIF_POLLER_EVENT_TRANSMIT))
+            return TRUE;
+
+        break;
+
+    default:
+        ASSERT(FALSE);
+        break;
+    }
+
+    return FALSE;
+}
+
+KSERVICE_ROUTINE    PollerChannelEvtchnCallback;
+
+BOOLEAN
+PollerChannelEvtchnCallback(
+    IN  PKINTERRUPT         InterruptObject,
+    IN  PVOID               Argument
+    )
+{
+    PXENVIF_POLLER_CHANNEL  Channel = Argument;
+    PXENVIF_POLLER_INSTANCE Instance;
+
+    UNREFERENCED_PARAMETER(InterruptObject);
+
+    ASSERT(Channel != NULL);
+    Instance = Channel->Instance;
+
+    Channel->Events++;
+
+    PollerChannelSetPending(Channel);
+
+    if (KeInsertQueueDpc(&Instance->Dpc, NULL, NULL))
+        Instance->Dpcs++;
+
+    return TRUE;
+}
+
+static FORCEINLINE BOOLEAN
+__PollerIsSplit(
+    IN  PXENVIF_POLLER  Poller
+    )
+{
+    return Poller->Split;
+}
+
+static NTSTATUS
+PollerChannelConnect(
+    IN  PXENVIF_POLLER_CHANNEL  Channel
+    )
+{
+    PXENVIF_POLLER_INSTANCE     Instance;
+    PXENVIF_POLLER              Poller;
+    PXENVIF_FRONTEND            Frontend;
+    PROCESSOR_NUMBER            ProcNumber;
+    NTSTATUS                    status;
+
+    Instance = Channel->Instance;
+    Poller = Instance->Poller;
+    Frontend = Poller->Frontend;
+
+    switch (Channel->Type)
+    {
+    case XENVIF_POLLER_CHANNEL_RECEIVER:
+    case XENVIF_POLLER_CHANNEL_TRANSMITTER:
+        if (!__PollerIsSplit(Poller))
+            goto done;
+
+        break;
+
+    case XENVIF_POLLER_CHANNEL_COMBINED:
+        if (__PollerIsSplit(Poller))
+            goto done;
+
+        break;
+
+    default:
+        ASSERT(FALSE);
+        break;
+    }
+
+    Channel->Channel = XENBUS_EVTCHN(Open,
+                                     &Poller->EvtchnInterface,
+                                     XENBUS_EVTCHN_TYPE_UNBOUND,
+                                     PollerChannelEvtchnCallback,
+                                     Channel,
+                                     FrontendGetBackendDomain(Frontend),
+                                     TRUE);
+
+    status = STATUS_UNSUCCESSFUL;
+    if (Channel->Channel == NULL)
+        goto fail1;
+
+    status = KeGetProcessorNumberFromIndex(Instance->Index, &ProcNumber);
+    ASSERT(NT_SUCCESS(status));
+
+    (VOID) XENBUS_EVTCHN(Bind,
+                         &Poller->EvtchnInterface,
+                         Channel->Channel,
+                         ProcNumber.Group,
+                         ProcNumber.Number);
+
+    XENBUS_EVTCHN(Unmask,
+                  &Poller->EvtchnInterface,
+                  Channel->Channel,
+                  FALSE);
+
+done:
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static NTSTATUS
+PollerChannelStoreWrite(
+    IN  PXENVIF_POLLER_CHANNEL      Channel,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction
+    )
+{
+    PXENVIF_POLLER_INSTANCE         Instance;
+    PXENVIF_POLLER                  Poller;
+    ULONG                           Port;
+    NTSTATUS                        status;
+
+    Instance = Channel->Instance;
+    Poller = Instance->Poller;
+
+    if (Channel->Channel == NULL)
+        goto done;
+
+    Port = XENBUS_EVTCHN(GetPort,
+                         &Poller->EvtchnInterface,
+                         Channel->Channel);
+
+    status = XENBUS_STORE(Printf,
+                          &Poller->StoreInterface,
+                          Transaction,
+                          Instance->Path,
+                          (PCHAR)Channel->Node,
+                          "%u",
+                          Port);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+done:
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static VOID
+PollerChannelUnmask(
+    IN  PXENVIF_POLLER_CHANNEL  Channel
+    )
+{
+    PXENVIF_POLLER_INSTANCE     Instance;
+    PXENVIF_POLLER              Poller;
+
+    Instance = Channel->Instance;
+    Poller = Instance->Poller;
+
+    if (Channel->Channel == NULL)
+        return;
+
+    if (!PollerChannelTestPending(Channel))
+        XENBUS_EVTCHN(Unmask,
+                      &Poller->EvtchnInterface,
+                      Channel->Channel,
+                      FALSE);
+}
+
+static VOID
+PollerChannelSend(
+    IN  PXENVIF_POLLER_CHANNEL  Channel
+    )
+{
+    PXENVIF_POLLER_INSTANCE     Instance;
+    PXENVIF_POLLER              Poller;
+
+    Instance = Channel->Instance;
+    Poller = Instance->Poller;
+
+    XENBUS_EVTCHN(Send,
+                  &Poller->EvtchnInterface,
+                  Channel->Channel);
+}
+
+static VOID
+PollerChannelDebugCallback(
+    IN  PXENVIF_POLLER_CHANNEL  Channel
+    )
+{
+    PXENVIF_POLLER_INSTANCE     Instance;
+    PXENVIF_POLLER              Poller;
+
+    Instance = Channel->Instance;
+    Poller = Instance->Poller;
+
+    if (Channel->Channel == NULL)
+        return;
+
+    XENBUS_DEBUG(Printf,
+                 &Poller->DebugInterface,
+                 "[%s]: Events = %lu\n",
+                 Channel->Node,
+                 Channel->Events);
+}
+
+static VOID
+PollerChannelDisconnect(
+    IN  PXENVIF_POLLER_CHANNEL  Channel
+    )
+{
+    PXENVIF_POLLER_INSTANCE     Instance;
+    PXENVIF_POLLER              Poller;
+
+    Instance = Channel->Instance;
+    Poller = Instance->Poller;
+
+    if (Channel->Channel == NULL)
+        return;
+
+    Channel->Events = 0;
+
+    XENBUS_EVTCHN(Close,
+                  &Poller->EvtchnInterface,
+                  Channel->Channel);
+    Channel->Channel = NULL;
+}
+
+static VOID
+PollerChannelTeardown(
+    IN  PXENVIF_POLLER_CHANNEL  Channel
+    )
+{
+    Channel->Node = NULL;
+
+    Channel->Type = 0;
+    Channel->Instance = NULL;
+
+    ASSERT(IsZeroMemory(Channel, sizeof (XENVIF_POLLER_CHANNEL)));
+    __PollerFree(Channel);
+}
+
+__drv_requiresIRQL(DISPATCH_LEVEL)
+static VOID
+PollerInstanceUnmask(
+    IN  PXENVIF_POLLER_INSTANCE     Instance,
+    IN  XENVIF_POLLER_EVENT_TYPE    Event
+    )
+{
+    PXENVIF_POLLER                  Poller;
+    XENVIF_POLLER_CHANNEL_TYPE      Type;
+    PXENVIF_POLLER_CHANNEL          Channel;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+    Poller = Instance->Poller;
+
+    KeAcquireSpinLockAtDpcLevel(&Instance->Lock);
+
+    if (!Instance->Enabled)
+        goto done;
+
+    if (!__PollerIsSplit(Poller)) {
+        Type = XENVIF_POLLER_CHANNEL_COMBINED;
+    } else {
+        switch (Event) {
+        case XENVIF_POLLER_EVENT_RECEIVE:
+            Type = XENVIF_POLLER_CHANNEL_RECEIVER;
+            break;
+
+        case XENVIF_POLLER_EVENT_TRANSMIT:
+            Type = XENVIF_POLLER_CHANNEL_TRANSMITTER;
+            break;
+
+        default:
+            Type = XENVIF_POLLER_CHANNEL_INVALID;
+            break;
+        }
+    }
+
+    ASSERT(Type != XENVIF_POLLER_CHANNEL_INVALID);
+
+    Channel = Instance->Channel[Type];
+
+    PollerChannelUnmask(Channel);
+
+done:
+    KeReleaseSpinLockFromDpcLevel(&Instance->Lock);
+}
+
+#define TIME_US(_us)        ((_us) * 10)
+#define TIME_MS(_ms)        (TIME_US((_ms) * 1000))
+#define TIME_S(_s)          (TIME_MS((_s) * 1000))
+#define TIME_RELATIVE(_t)   (-(_t))
+
+__drv_requiresIRQL(DISPATCH_LEVEL)
+static VOID
+PollerInstanceDefer(
+    IN  PXENVIF_POLLER_INSTANCE Instance
+    )
+{
+    LARGE_INTEGER               Delay;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+    KeAcquireSpinLockAtDpcLevel(&Instance->Lock);
+
+    if (!Instance->Enabled)
+        goto done;
+
+    Delay.QuadPart = TIME_RELATIVE(TIME_US(100));
+    KeSetTimer(&Instance->Timer, Delay, &Instance->TimerDpc);
+
+done:
+    KeReleaseSpinLockFromDpcLevel(&Instance->Lock);
+}
+
+static FORCEINLINE BOOLEAN
+PollerInstanceDpcTimeout(
+    IN  PXENVIF_POLLER_INSTANCE Instance
+    )
+{
+    KDPC_WATCHDOG_INFORMATION   Watchdog;
+    NTSTATUS                    status;
+
+    UNREFERENCED_PARAMETER(Instance);
+
+    RtlZeroMemory(&Watchdog, sizeof (Watchdog));
+
+    status = KeQueryDpcWatchdogInformation(&Watchdog);
+    ASSERT(NT_SUCCESS(status));
+
+    if (Watchdog.DpcTimeLimit == 0 ||
+        Watchdog.DpcWatchdogLimit == 0)
+        return FALSE;
+
+    if (Watchdog.DpcTimeCount > (Watchdog.DpcTimeLimit / 2) &&
+        Watchdog.DpcWatchdogCount > (Watchdog.DpcWatchdogLimit / 2))
+        return FALSE;
+
+    return TRUE;
+}
+
+__drv_functionClass(KDEFERRED_ROUTINE)
+__drv_maxIRQL(DISPATCH_LEVEL)
+__drv_minIRQL(DISPATCH_LEVEL)
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__drv_sameIRQL
+static VOID
+PollerInstanceDpc(
+    IN  PKDPC               Dpc,
+    IN  PVOID               Context,
+    IN  PVOID               Argument1,
+    IN  PVOID               Argument2
+    )
+{
+    PXENVIF_POLLER_INSTANCE Instance = Context;
+    PXENVIF_POLLER          Poller;
+    PXENVIF_FRONTEND        Frontend;
+    BOOLEAN                 NeedReceiverPoll;
+    BOOLEAN                 NeedTransmitterPoll;
+
+    UNREFERENCED_PARAMETER(Dpc);
+    UNREFERENCED_PARAMETER(Argument1);
+    UNREFERENCED_PARAMETER(Argument2);
+
+    ASSERT(Instance != NULL);
+
+    Poller = Instance->Poller;
+    Frontend = Poller->Frontend;
+
+    NeedReceiverPoll = FALSE;
+    NeedTransmitterPoll = FALSE;
+
+    for (;;) {
+        NeedReceiverPoll |=
+            (InterlockedBitTestAndReset(&Instance->Pending,
+                                        XENVIF_POLLER_EVENT_RECEIVE) != 0) ?
+            TRUE :
+            FALSE;
+
+        NeedTransmitterPoll |=
+            (InterlockedBitTestAndReset(&Instance->Pending,
+                                        XENVIF_POLLER_EVENT_TRANSMIT) != 0) ?
+            TRUE :
+            FALSE;
+
+        if (!NeedReceiverPoll && !NeedTransmitterPoll)
+            break;
+
+        if (NeedReceiverPoll)
+        {
+            BOOLEAN Retry = ReceiverPoll(FrontendGetReceiver(Frontend),
+                                         Instance->Index);
+
+            if (!Retry) {
+                NeedReceiverPoll = FALSE;
+                PollerInstanceUnmask(Instance, XENVIF_POLLER_EVENT_RECEIVE);
+            }
+        }
+        if (NeedTransmitterPoll)
+        {
+            BOOLEAN Retry = TransmitterPoll(FrontendGetTransmitter(Frontend),
+                                            Instance->Index);
+
+            if (!Retry) {
+                NeedTransmitterPoll = FALSE;
+                PollerInstanceUnmask(Instance, XENVIF_POLLER_EVENT_TRANSMIT);
+            }
+        }
+
+        if (PollerInstanceDpcTimeout(Instance)) {
+            PollerInstanceDefer(Instance);
+            break;
+        }
+    }
+}
+
+static NTSTATUS
+PollerInstanceInitialize(
+    IN  PXENVIF_POLLER          Poller,
+    IN  LONG                    Index,
+    OUT PXENVIF_POLLER_INSTANCE *Instance
+    )
+{
+    PXENVIF_FRONTEND            Frontend;
+    LONG                        Type;
+    NTSTATUS                    status;
+
+    Frontend = Poller->Frontend;
+
+    *Instance = __PollerAllocate(sizeof (XENVIF_POLLER_INSTANCE));
+
+    status = STATUS_NO_MEMORY;
+    if (*Instance == NULL)
+        goto fail1;
+
+    (*Instance)->Poller = Poller;
+    (*Instance)->Index = Index;
+
+    for (Type = 0; Type < XENVIF_POLLER_CHANNEL_TYPE_COUNT; Type++)
+    {
+        PXENVIF_POLLER_CHANNEL Channel;
+
+        status = PollerChannelInitialize(*Instance, Type, &Channel);
+        if (!NT_SUCCESS(status))
+            goto fail2;
+
+        (*Instance)->Channel[Type] = Channel;
+    }
+
+    (*Instance)->Path = FrontendFormatPath(Frontend, Index);
+    if ((*Instance)->Path == NULL)
+        goto fail3;
+
+    KeInitializeSpinLock(&(*Instance)->Lock);
+
+    KeInitializeDpc(&(*Instance)->Dpc, PollerInstanceDpc, *Instance);
+    KeInitializeTimer(&(*Instance)->Timer);
+    KeInitializeDpc(&(*Instance)->TimerDpc, PollerInstanceDpc, *Instance);
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+    Type = XENVIF_POLLER_CHANNEL_TYPE_COUNT;
+
+fail2:
+    Error("fail2\n");
+
+    while (--Type >= 0)
+    {
+        PXENVIF_POLLER_CHANNEL Channel = (*Instance)->Channel[Type];
+
+        (*Instance)->Channel[Type] = NULL;
+        PollerChannelTeardown(Channel);
+    }
+
+    (*Instance)->Index = 0;
+    (*Instance)->Poller = NULL;
+
+    ASSERT(IsZeroMemory(*Instance, sizeof (XENVIF_POLLER_INSTANCE)));
+    __PollerFree(*Instance);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+__drv_requiresIRQL(DISPATCH_LEVEL)
+static NTSTATUS
+PollerInstanceConnect(
+    IN  PXENVIF_POLLER_INSTANCE Instance
+    )
+{
+    PROCESSOR_NUMBER            ProcNumber;
+    LONG                        Type;
+    NTSTATUS                    status;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+    status = KeGetProcessorNumberFromIndex(Instance->Index, &ProcNumber);
+    ASSERT(NT_SUCCESS(status));
+
+    KeSetTargetProcessorDpcEx(&Instance->Dpc, &ProcNumber);
+    KeSetTargetProcessorDpcEx(&Instance->TimerDpc, &ProcNumber);
+
+    for (Type = 0; Type < XENVIF_POLLER_CHANNEL_TYPE_COUNT; Type++)
+    {
+        PXENVIF_POLLER_CHANNEL Channel = Instance->Channel[Type];
+
+        status = PollerChannelConnect(Channel);
+        if (!NT_SUCCESS(status))
+            goto fail1;
+    }
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    while (--Type >= 0)
+    {
+        PXENVIF_POLLER_CHANNEL Channel = Instance->Channel[Type];
+
+        PollerChannelDisconnect(Channel);
+    }
+
+    return status;
+}
+
+static NTSTATUS
+PollerInstanceStoreWrite(
+    IN  PXENVIF_POLLER_INSTANCE     Instance,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction
+    )
+{
+    ULONG                           Type;
+    NTSTATUS                        status;
+
+    for (Type = 0; Type < XENVIF_POLLER_CHANNEL_TYPE_COUNT; Type++)
+    {
+        PXENVIF_POLLER_CHANNEL Channel = Instance->Channel[Type];
+
+        status = PollerChannelStoreWrite(Channel, Transaction);
+        if (!NT_SUCCESS(status))
+            goto fail1;
+    }
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
 
-static FORCEINLINE PVOID
-__PollerAllocate(
-    IN  ULONG   Length
+__drv_requiresIRQL(DISPATCH_LEVEL)
+static NTSTATUS
+PollerInstanceEnable(
+    IN  PXENVIF_POLLER_INSTANCE Instance
     )
 {
-    return __AllocatePoolWithTag(NonPagedPool, Length, XENVIF_POLLER_TAG);
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+    (VOID) InterlockedBitTestAndSet(&Instance->Pending,
+                                    XENVIF_POLLER_EVENT_RECEIVE);
+    (VOID) InterlockedBitTestAndSet(&Instance->Pending,
+                                    XENVIF_POLLER_EVENT_TRANSMIT);
+
+    KeAcquireSpinLockAtDpcLevel(&Instance->Lock);
+    Instance->Enabled = TRUE;
+    KeReleaseSpinLockFromDpcLevel(&Instance->Lock);
+
+    (VOID) KeInsertQueueDpc(&Instance->Dpc, NULL, NULL);
+
+    return STATUS_SUCCESS;
 }
 
-static FORCEINLINE VOID
-__PollerFree(
-    IN  PVOID   Buffer
+__drv_requiresIRQL(DISPATCH_LEVEL)
+static NTSTATUS
+PollerInstanceSend(
+    IN  PXENVIF_POLLER_INSTANCE     Instance,
+    IN  XENVIF_POLLER_EVENT_TYPE    Event
     )
 {
-    __FreePoolWithTag(Buffer, XENVIF_POLLER_TAG);
+    PXENVIF_POLLER                  Poller;
+    XENVIF_POLLER_CHANNEL_TYPE      Type;
+    PXENVIF_POLLER_CHANNEL          Channel;
+    NTSTATUS                        status;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+    Poller = Instance->Poller;
+
+    KeAcquireSpinLockAtDpcLevel(&Instance->Lock);
+
+    Type = XENVIF_POLLER_CHANNEL_INVALID;
+
+    if (Instance->Enabled) {
+        if (!__PollerIsSplit(Poller)) {
+            Type = XENVIF_POLLER_CHANNEL_COMBINED;
+        } else {
+            switch (Event) {
+            case XENVIF_POLLER_EVENT_RECEIVE:
+                Type = XENVIF_POLLER_CHANNEL_RECEIVER;
+                break;
+
+            case XENVIF_POLLER_EVENT_TRANSMIT:
+                Type = XENVIF_POLLER_CHANNEL_TRANSMITTER;
+                break;
+
+            default:
+                ASSERT(FALSE);
+                break;
+            }
+        }
+    }
+
+    KeReleaseSpinLockFromDpcLevel(&Instance->Lock);
+
+    status = STATUS_UNSUCCESSFUL;
+    if (Type == XENVIF_POLLER_CHANNEL_INVALID)
+        goto fail1;
+
+    Channel = Instance->Channel[Type];
+
+    PollerChannelSend(Channel);
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+__drv_requiresIRQL(DISPATCH_LEVEL)
+static NTSTATUS
+PollerInstanceTrigger(
+    IN  PXENVIF_POLLER_INSTANCE     Instance,
+    IN  XENVIF_POLLER_EVENT_TYPE    Event
+    )
+{
+    NTSTATUS                        status;
+
+    status = STATUS_INVALID_PARAMETER;
+    if (Event >= XENVIF_POLLER_EVENT_TYPE_COUNT)
+        goto fail1;
+
+    (VOID) InterlockedBitTestAndSet(&Instance->Pending, Event);
+
+    if (KeInsertQueueDpc(&Instance->Dpc, NULL, NULL))
+        Instance->Dpcs++;
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static VOID
+PollerInstanceDebugCallback(
+    IN  PXENVIF_POLLER_INSTANCE Instance
+    )
+{
+    PXENVIF_POLLER              Poller;
+    ULONG                       Type;
+
+    Poller = Instance->Poller;
+
+    XENBUS_DEBUG(Printf,
+                 &Poller->DebugInterface,
+                 "[%d]: Dpcs = %lu\n",
+                 Instance->Index,
+                 Instance->Dpcs);
+
+    for (Type = 0; Type < XENVIF_POLLER_CHANNEL_TYPE_COUNT; Type++)
+    {
+        PXENVIF_POLLER_CHANNEL Channel = Instance->Channel[Type];
+
+        PollerChannelDebugCallback(Channel);
+    }
+}
+
+__drv_requiresIRQL(DISPATCH_LEVEL)
+static VOID
+PollerInstanceDisable(
+    IN  PXENVIF_POLLER_INSTANCE Instance
+    )
+{
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+    KeAcquireSpinLockAtDpcLevel(&Instance->Lock);
+    Instance->Enabled = FALSE;
+    KeReleaseSpinLockFromDpcLevel(&Instance->Lock);
+
+    //
+    // No new timers can be scheduled once Enabled goes to FALSE.
+    // Cancel any existing ones.
+    //
+    (VOID) KeCancelTimer(&Instance->Timer);
+}
+
+__drv_requiresIRQL(DISPATCH_LEVEL)
+static VOID
+PollerInstanceDisconnect(
+    IN  PXENVIF_POLLER_INSTANCE Instance
+    )
+{
+    LONG                        Type;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+    Instance->Dpcs = 0;
+    Instance->Pending = 0;
+
+    Type = XENVIF_POLLER_CHANNEL_TYPE_COUNT;
+
+    while (--Type >= 0)
+    {
+        PXENVIF_POLLER_CHANNEL Channel = Instance->Channel[Type];
+
+        PollerChannelDisconnect(Channel);
+    }
+}
+
+static VOID
+PollerInstanceTeardown(
+    IN  PXENVIF_POLLER_INSTANCE Instance
+    )
+{
+    PXENVIF_POLLER              Poller;
+    PXENVIF_FRONTEND            Frontend;
+    LONG                        Type;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+    KeFlushQueuedDpcs();
+
+    Poller = Instance->Poller;
+    Frontend = Poller->Frontend;
+
+    RtlZeroMemory(&Instance->TimerDpc, sizeof (KDPC));
+    RtlZeroMemory(&Instance->Timer, sizeof (KTIMER));
+    RtlZeroMemory(&Instance->Dpc, sizeof (KDPC));
+
+    RtlZeroMemory(&Instance->Lock, sizeof (KSPIN_LOCK));
+
+    FrontendFreePath(Frontend, Instance->Path);
+    Instance->Path = NULL;
+
+    Type = XENVIF_POLLER_CHANNEL_TYPE_COUNT;
+
+    while (--Type >= 0)
+    {
+        PXENVIF_POLLER_CHANNEL Channel = Instance->Channel[Type];
+
+        Instance->Channel[Type] = NULL;
+        PollerChannelTeardown(Channel);
+    }
+
+    Instance->Index = 0;
+    Instance->Poller = NULL;
+
+    ASSERT(IsZeroMemory(Instance, sizeof (XENVIF_POLLER_INSTANCE)));
+    __PollerFree(Instance);
 }
 
 static VOID
 PollerDebugCallback(
-    IN  PVOID   Argument,
-    IN  BOOLEAN Crashing
+    IN  PVOID           Argument,
+    IN  BOOLEAN         Crashing
     )
 {
-    UNREFERENCED_PARAMETER(Argument);
+    PXENVIF_POLLER      Poller = Argument;
+    PXENVIF_FRONTEND    Frontend;
+    ULONG               NumQueues;
+    ULONG               Index;
+
     UNREFERENCED_PARAMETER(Crashing);
+
+    Frontend = Poller->Frontend;
+
+    NumQueues = FrontendGetNumQueues(Frontend);
+
+    for (Index = 0; Index < NumQueues; Index++) {
+        PXENVIF_POLLER_INSTANCE Instance = Poller->Instance[Index];
+
+        PollerInstanceDebugCallback(Instance);
+    }
+}
+
+static VOID
+PollerSetSplit(
+    IN  PXENVIF_POLLER  Poller
+    )
+{
+    PXENVIF_FRONTEND    Frontend;
+    PCHAR               Buffer;
+    NTSTATUS            status;
+
+    Frontend = Poller->Frontend;
+
+    status = XENBUS_STORE(Read,
+                          &Poller->StoreInterface,
+                          NULL,
+                          FrontendGetBackendPath(Frontend),
+                          "feature-split-event-channels",
+                          &Buffer);
+    if (NT_SUCCESS(status)) {
+        Poller->Split = (BOOLEAN)strtol(Buffer, NULL, 2);
+
+        XENBUS_STORE(Free,
+                     &Poller->StoreInterface,
+                     Buffer);
+    } else {
+        Poller->Split = FALSE;
+    }
+
+    Info("%s: %s\n", FrontendGetPath(Frontend),
+         (Poller->Split) ? "TRUE" : "FALSE");
 }
 
 NTSTATUS
@@ -92,6 +1069,8 @@ PollerInitialize(
     OUT PXENVIF_POLLER      *Poller
     )
 {
+    LONG                    MaxQueues;
+    LONG                    Index;
     NTSTATUS                status;
 
     *Poller = __PollerAllocate(sizeof (XENVIF_POLLER));
@@ -100,13 +1079,67 @@ PollerInitialize(
     if (*Poller == NULL)
         goto fail1;
 
+    FdoGetEvtchnInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+                          &(*Poller)->EvtchnInterface);
+
+    FdoGetStoreInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+                         &(*Poller)->StoreInterface);
+
     FdoGetDebugInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
                          &(*Poller)->DebugInterface);
 
     (*Poller)->Frontend = Frontend;
 
+    MaxQueues = FrontendGetMaxQueues(Frontend);
+    (*Poller)->Instance = __PollerAllocate(sizeof (PXENVIF_POLLER_INSTANCE) *
+                                           MaxQueues);
+
+    status = STATUS_NO_MEMORY;
+    if ((*Poller)->Instance == NULL)
+        goto fail2;
+
+    for (Index = 0; Index < MaxQueues; Index++) {
+        PXENVIF_POLLER_INSTANCE Instance;
+
+        status = PollerInstanceInitialize(*Poller, Index, &Instance);
+        if (!NT_SUCCESS(status))
+            goto fail3;
+
+        (*Poller)->Instance[Index] = Instance;
+    }
+
     return STATUS_SUCCESS;
 
+fail3:
+    Error("fail3\n");
+
+    while (--Index >= 0)
+    {
+        PXENVIF_POLLER_INSTANCE Instance = (*Poller)->Instance[Index];
+
+        (*Poller)->Instance[Index] = NULL;
+        PollerInstanceTeardown(Instance);
+    }
+
+    ASSERT(IsZeroMemory((*Poller)->Instance,
+                        sizeof (PXENVIF_POLLER_INSTANCE) * MaxQueues));
+    __PollerFree((*Poller)->Instance);
+    (*Poller)->Instance = NULL;
+
+fail2:
+    Error("fail2\n");
+
+    (*Poller)->Frontend = NULL;
+
+    RtlZeroMemory(&(*Poller)->DebugInterface,
+                  sizeof (XENBUS_DEBUG_INTERFACE));
+
+    RtlZeroMemory(&(*Poller)->StoreInterface,
+                  sizeof (XENBUS_STORE_INTERFACE));
+
+    RtlZeroMemory(&(*Poller)->EvtchnInterface,
+                  sizeof (XENBUS_EVTCHN_INTERFACE));
+
 fail1:
     Error("fail1 (%08x)\n", status);
 
@@ -118,14 +1151,39 @@ PollerConnect(
     IN  PXENVIF_POLLER  Poller
     )
 {
+    PXENVIF_FRONTEND    Frontend;
+    LONG                NumQueues;
+    LONG                Index;
     NTSTATUS            status;
 
     Trace("====>\n");
 
-    status = XENBUS_DEBUG(Acquire, &Poller->DebugInterface);
+    Frontend = Poller->Frontend;
+
+    status = XENBUS_EVTCHN(Acquire, &Poller->EvtchnInterface);
     if (!NT_SUCCESS(status))
         goto fail1;
 
+    status = XENBUS_STORE(Acquire, &Poller->StoreInterface);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = XENBUS_DEBUG(Acquire, &Poller->DebugInterface);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    PollerSetSplit(Poller);
+
+    NumQueues = FrontendGetNumQueues(Frontend);
+
+    for (Index = 0; Index < NumQueues; Index++) {
+        PXENVIF_POLLER_INSTANCE Instance = Poller->Instance[Index];
+
+        status = PollerInstanceConnect(Instance);
+        if (!NT_SUCCESS(status))
+            goto fail4;
+    }
+
     status = XENBUS_DEBUG(Register,
                           &Poller->DebugInterface,
                           __MODULE__ "|POLLER",
@@ -133,15 +1191,39 @@ PollerConnect(
                           Poller,
                           &Poller->DebugCallback);
     if (!NT_SUCCESS(status))
-        goto fail2;
+        goto fail5;
 
     Trace("<====\n");
     return STATUS_SUCCESS;
 
+fail5:
+    Error("fail5\n");
+
+    Index = NumQueues;
+
+fail4:
+    Error("fail4\n");
+
+    while (--Index >= 0)
+    {
+        PXENVIF_POLLER_INSTANCE Instance = Poller->Instance[Index];
+
+        PollerInstanceDisconnect(Instance);
+    }
+
+    Poller->Split = FALSE;
+
+    XENBUS_DEBUG(Release, &Poller->DebugInterface);
+
+fail3:
+    Error("fail3\n");
+
+    XENBUS_STORE(Release, &Poller->StoreInterface);
+
 fail2:
     Error("fail2\n");
 
-    XENBUS_DEBUG(Release, &Poller->DebugInterface);
+    XENBUS_EVTCHN(Release, &Poller->EvtchnInterface);
 
 fail1:
     Error("fail1 (%08x)\n", status);
@@ -155,34 +1237,174 @@ PollerStoreWrite(
     IN  PXENBUS_STORE_TRANSACTION   Transaction
     )
 {
-    UNREFERENCED_PARAMETER(Poller);
-    UNREFERENCED_PARAMETER(Transaction);
+    PXENVIF_FRONTEND                Frontend;
+    LONG                            NumQueues;
+    LONG                            Index;
+    NTSTATUS                        status;
+
+    Trace("====>\n");
+
+    Frontend = Poller->Frontend;
+
+    NumQueues = FrontendGetNumQueues(Frontend);
+
+    for (Index = 0; Index < NumQueues; Index++) {
+        PXENVIF_POLLER_INSTANCE Instance = Poller->Instance[Index];
 
-    Trace("<===>\n");
+        status = PollerInstanceStoreWrite(Instance, Transaction);
+        if (!NT_SUCCESS(status))
+            goto fail1;
+    }
+
+    Trace("<====\n");
 
     return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
 }
 
 NTSTATUS
 PollerEnable(
-    IN  PXENVIF_POLLER      Poller
+    IN  PXENVIF_POLLER  Poller
+    )
+{
+    PXENVIF_FRONTEND    Frontend;
+    LONG                NumQueues;
+    LONG                Index;
+    NTSTATUS            status;
+
+    Trace("====>\n");
+
+    Frontend = Poller->Frontend;
+
+    NumQueues = FrontendGetNumQueues(Frontend);
+
+    for (Index = 0; Index < NumQueues; Index++) {
+        PXENVIF_POLLER_INSTANCE Instance = Poller->Instance[Index];
+
+        status = PollerInstanceEnable(Instance);
+        if (!NT_SUCCESS(status))
+            goto fail1;
+    }
+
+    Trace("<====\n");
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    while (--Index >= 0)
+    {
+        PXENVIF_POLLER_INSTANCE Instance = Poller->Instance[Index];
+
+        PollerInstanceDisable(Instance);
+    }
+
+    return status;
+}
+
+NTSTATUS
+PollerSend(
+    IN  PXENVIF_POLLER              Poller,
+    IN  ULONG                       Index,
+    IN  XENVIF_POLLER_EVENT_TYPE    Event
     )
 {
-    UNREFERENCED_PARAMETER(Poller);
+    PXENVIF_FRONTEND                Frontend;
+    ULONG                           NumQueues;
+    PXENVIF_POLLER_INSTANCE         Instance;
+    NTSTATUS                        status;
 
-    Trace("<===>\n");
+    Frontend = Poller->Frontend;
+
+    NumQueues = FrontendGetNumQueues(Frontend);
+
+    status = STATUS_INVALID_PARAMETER;
+    if (Index >= NumQueues)
+        goto fail1;
+
+    Instance = Poller->Instance[Index];
+
+    status = PollerInstanceSend(Instance, Event);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+PollerTrigger(
+    IN  PXENVIF_POLLER              Poller,
+    IN  ULONG                       Index,
+    IN  XENVIF_POLLER_EVENT_TYPE    Event
+    )
+{
+    PXENVIF_FRONTEND                Frontend;
+    ULONG                           NumQueues;
+    PXENVIF_POLLER_INSTANCE         Instance;
+    NTSTATUS                        status;
+
+    Frontend = Poller->Frontend;
+
+    NumQueues = FrontendGetNumQueues(Frontend);
+
+    status = STATUS_INVALID_PARAMETER;
+    if (Index >= NumQueues)
+        goto fail1;
+
+    Instance = Poller->Instance[Index];
+
+    status = PollerInstanceTrigger(Instance, Event);
+    if (!NT_SUCCESS(status))
+        goto fail2;
 
     return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
 }
 
 VOID
 PollerDisable(
-    IN  PXENVIF_POLLER      Poller
+    IN  PXENVIF_POLLER  Poller
     )
 {
-    UNREFERENCED_PARAMETER(Poller);
+    PXENVIF_FRONTEND    Frontend;
+    LONG                NumQueues;
+    LONG                Index;
 
-    Trace("<===>\n");
+    Trace("====>\n");
+
+    Frontend = Poller->Frontend;
+
+    NumQueues = FrontendGetNumQueues(Frontend);
+    Index = NumQueues;
+
+    while (--Index >= 0)
+    {
+        PXENVIF_POLLER_INSTANCE Instance = Poller->Instance[Index];
+
+        PollerInstanceDisable(Instance);
+    }
+
+    Trace("<====\n");
 }
 
 VOID
@@ -190,15 +1412,37 @@ PollerDisconnect(
     IN  PXENVIF_POLLER  Poller
     )
 {
+    PXENVIF_FRONTEND    Frontend;
+    LONG                NumQueues;
+    LONG                Index;
+
     Trace("====>\n");
 
+    Frontend = Poller->Frontend;
+
     XENBUS_DEBUG(Deregister,
                  &Poller->DebugInterface,
                  Poller->DebugCallback);
     Poller->DebugCallback = NULL;
 
+    NumQueues = FrontendGetNumQueues(Frontend);
+    Index = NumQueues;
+
+    while (--Index >= 0)
+    {
+        PXENVIF_POLLER_INSTANCE Instance = Poller->Instance[Index];
+
+        PollerInstanceDisconnect(Instance);
+    }
+
+    Poller->Split = FALSE;
+
     XENBUS_DEBUG(Release, &Poller->DebugInterface);
 
+    XENBUS_STORE(Release, &Poller->StoreInterface);
+
+    XENBUS_EVTCHN(Release, &Poller->EvtchnInterface);
+
     Trace("<====\n");
 }
 
@@ -207,11 +1451,41 @@ PollerTeardown(
     IN  PXENVIF_POLLER  Poller
     )
 {
+    PXENVIF_FRONTEND    Frontend;
+    LONG                MaxQueues;
+    LONG                Index;
+
     ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
 
+    Frontend = Poller->Frontend;
+
+    MaxQueues = FrontendGetMaxQueues(Frontend);
+    Index = MaxQueues;
+
+    while (--Index >= 0)
+    {
+        PXENVIF_POLLER_INSTANCE Instance = Poller->Instance[Index];
+
+        Poller->Instance[Index] = NULL;
+        PollerInstanceTeardown(Instance);
+    }
+
+    ASSERT(IsZeroMemory(Poller->Instance,
+                        sizeof (PXENVIF_POLLER_INSTANCE) * MaxQueues));
+    __PollerFree(Poller->Instance);
+    Poller->Instance = NULL;
+
+    Poller->Frontend = NULL;
+
     RtlZeroMemory(&Poller->DebugInterface,
                   sizeof (XENBUS_DEBUG_INTERFACE));
 
+    RtlZeroMemory(&Poller->StoreInterface,
+                  sizeof (XENBUS_STORE_INTERFACE));
+
+    RtlZeroMemory(&Poller->EvtchnInterface,
+                  sizeof (XENBUS_EVTCHN_INTERFACE));
+
     ASSERT(IsZeroMemory(Poller, sizeof (XENVIF_POLLER)));
     __PollerFree(Poller);
 }
diff --git a/src/xenvif/poller.h b/src/xenvif/poller.h
index 5ba0eaa..a2b32a1 100644
--- a/src/xenvif/poller.h
+++ b/src/xenvif/poller.h
@@ -40,10 +40,16 @@
 
 typedef struct _XENVIF_POLLER XENVIF_POLLER, *PXENVIF_POLLER;
 
+typedef enum _XENVIF_POLLER_EVENT_TYPE {
+    XENVIF_POLLER_EVENT_RECEIVE,
+    XENVIF_POLLER_EVENT_TRANSMIT,
+    XENVIF_POLLER_EVENT_TYPE_COUNT
+} XENVIF_POLLER_EVENT_TYPE, *PXENVIF_POLLER_EVENT_TYPE;
+
 extern NTSTATUS
 PollerInitialize(
     IN  PXENVIF_FRONTEND    Frontend,
-    OUT PXENVIF_POLLER  *Poller
+    OUT PXENVIF_POLLER      *Poller
     );
 
 extern NTSTATUS
@@ -53,7 +59,7 @@ PollerConnect(
 
 extern NTSTATUS
 PollerStoreWrite(
-    IN  PXENVIF_POLLER          Poller,
+    IN  PXENVIF_POLLER              Poller,
     IN  PXENBUS_STORE_TRANSACTION   Transaction
     );
 
@@ -62,6 +68,20 @@ PollerEnable(
     IN  PXENVIF_POLLER  Poller
     );
 
+extern NTSTATUS
+PollerSend(
+    IN  PXENVIF_POLLER              Poller,
+    IN  ULONG                       Index,
+    IN  XENVIF_POLLER_EVENT_TYPE    Event
+    );
+
+extern NTSTATUS
+PollerTrigger(
+    IN  PXENVIF_POLLER              Poller,
+    IN  ULONG                       Index,
+    IN  XENVIF_POLLER_EVENT_TYPE    Event
+    );
+
 extern VOID
 PollerDisable(
     IN  PXENVIF_POLLER  Poller
diff --git a/src/xenvif/receiver.c b/src/xenvif/receiver.c
index d7f3870..e48b678 100644
--- a/src/xenvif/receiver.c
+++ b/src/xenvif/receiver.c
@@ -41,7 +41,6 @@
 #include <store_interface.h>
 #include <cache_interface.h>
 #include <gnttab_interface.h>
-#include <evtchn_interface.h>
 
 #include "pdo.h"
 #include "registry.h"
@@ -88,12 +87,6 @@ typedef struct _XENVIF_RECEIVER_RING {
     netif_rx_front_ring_t       Front;
     netif_rx_sring_t            *Shared;
     PXENBUS_GNTTAB_ENTRY        Entry;
-    PXENBUS_EVTCHN_CHANNEL      Channel;
-    KDPC                        Dpc;
-    ULONG                       Dpcs;
-    KTIMER                      Timer;
-    KDPC                        TimerDpc;
-    ULONG                       Events;
     PXENVIF_RECEIVER_FRAGMENT   Pending[XENVIF_RECEIVER_MAXIMUM_FRAGMENT_ID + 
1];
     ULONG                       RequestsPosted;
     ULONG                       RequestsPushed;
@@ -128,7 +121,6 @@ struct _XENVIF_RECEIVER {
     PXENVIF_FRONTEND                Frontend;
     XENBUS_CACHE_INTERFACE          CacheInterface;
     XENBUS_GNTTAB_INTERFACE         GnttabInterface;
-    XENBUS_EVTCHN_INTERFACE         EvtchnInterface;
     PXENVIF_RECEIVER_RING           *Ring;
     LONG                            Loaned;
     LONG                            Returned;
@@ -1615,58 +1607,19 @@ __ReceiverRingIsStopped(
 }
 
 static FORCEINLINE VOID
-__ReceiverRingTrigger(
-    IN  PXENVIF_RECEIVER_RING   Ring,
-    IN  BOOLEAN                 Locked
-    )
-{
-    PXENVIF_RECEIVER            Receiver;
-
-    Receiver = Ring->Receiver;
-
-    if (!Locked)
-        __ReceiverRingAcquireLock(Ring);
-
-    if (Ring->Connected)
-        (VOID) XENBUS_EVTCHN(Trigger,
-                             &Receiver->EvtchnInterface,
-                             Ring->Channel);
-
-    if (!Locked)
-        __ReceiverRingReleaseLock(Ring);
-}
-
-static FORCEINLINE VOID
-__ReceiverRingSend(
-    IN  PXENVIF_RECEIVER_RING   Ring,
-    IN  BOOLEAN                 Locked
-    )
-{
-    PXENVIF_RECEIVER            Receiver;
-
-    Receiver = Ring->Receiver;
-
-    if (!Locked)
-        __ReceiverRingAcquireLock(Ring);
-
-    if (Ring->Connected)
-        (VOID) XENBUS_EVTCHN(Send,
-                             &Receiver->EvtchnInterface,
-                             Ring->Channel);
-
-    if (!Locked)
-        __ReceiverRingReleaseLock(Ring);
-}
-
-static FORCEINLINE VOID
 __ReceiverRingReturnPacket(
     IN  PXENVIF_RECEIVER_RING   Ring,
     IN  PXENVIF_RECEIVER_PACKET Packet,
     IN  BOOLEAN                 Locked
     )
 {
+    PXENVIF_RECEIVER            Receiver;
+    PXENVIF_FRONTEND            Frontend;
     PMDL                        Mdl;
 
+    Receiver = Ring->Receiver;
+    Frontend = Receiver->Frontend;
+
     Mdl = &Packet->Mdl;
 
     while (Mdl != NULL) {
@@ -1690,7 +1643,9 @@ __ReceiverRingReturnPacket(
 
         if (__ReceiverRingIsStopped(Ring)) {
             __ReceiverRingStart(Ring);
-            __ReceiverRingTrigger(Ring, TRUE);
+            PollerTrigger(FrontendGetPoller(Frontend),
+                          Ring->Index,
+                          XENVIF_POLLER_EVENT_RECEIVE);
         }
 
         if (!Locked)
@@ -1770,8 +1725,17 @@ __ReceiverRingPushRequests(
 
 #pragma warning (pop)
 
-    if (Notify)
-        __ReceiverRingSend(Ring, TRUE);
+    if (Notify) {
+        PXENVIF_RECEIVER    Receiver;
+        PXENVIF_FRONTEND    Frontend;
+
+        Receiver = Ring->Receiver;
+        Frontend = Receiver->Frontend;
+
+        PollerSend(FrontendGetPoller(Frontend),
+                   Ring->Index,
+                   XENVIF_POLLER_EVENT_RECEIVE);
+    }
 
     Ring->RequestsPushed = Ring->RequestsPosted;
 }
@@ -1927,14 +1891,6 @@ ReceiverRingDebugCallback(
                  Ring->RequestsPosted,
                  Ring->RequestsPushed,
                  Ring->ResponsesProcessed);
-
-    // Dump event channel
-    XENBUS_DEBUG(Printf,
-                 &Receiver->DebugInterface,
-                 "[%s]: Events = %lu Dpcs = %lu\n",
-                 FrontendIsSplit(Frontend) ? "RX" : "COMBINED",
-                 Ring->Events,
-                 Ring->Dpcs);
 }
 
 static DECLSPEC_NOINLINE BOOLEAN
@@ -2182,130 +2138,11 @@ done:
 #undef  XENVIF_RECEIVER_BATCH
 }
 
-static FORCEINLINE VOID
-__ReceiverRingUnmask(
-    IN  PXENVIF_RECEIVER_RING   Ring
-    )
-{
-    PXENVIF_RECEIVER            Receiver;
-
-    if (!Ring->Connected)
-        return;
-
-    Receiver = Ring->Receiver;
-
-    XENBUS_EVTCHN(Unmask,
-                  &Receiver->EvtchnInterface,
-                  Ring->Channel,
-                  FALSE);
-}
-
-static FORCEINLINE BOOLEAN
-__ReceiverRingDpcTimeout(
-    IN  PXENVIF_RECEIVER_RING   Ring
-    )
-{
-    KDPC_WATCHDOG_INFORMATION   Watchdog;
-    NTSTATUS                    status;
-
-    UNREFERENCED_PARAMETER(Ring);
-
-    RtlZeroMemory(&Watchdog, sizeof (Watchdog));
-
-    status = KeQueryDpcWatchdogInformation(&Watchdog);
-    ASSERT(NT_SUCCESS(status));
-
-    if (Watchdog.DpcTimeLimit == 0 ||
-        Watchdog.DpcWatchdogLimit == 0)
-        return FALSE;
-
-    if (Watchdog.DpcTimeCount > (Watchdog.DpcTimeLimit / 2) &&
-        Watchdog.DpcWatchdogCount > (Watchdog.DpcWatchdogLimit / 2))
-        return FALSE;
-
-    return TRUE;
-}
-
 #define TIME_US(_us)        ((_us) * 10)
 #define TIME_MS(_ms)        (TIME_US((_ms) * 1000))
 #define TIME_S(_s)          (TIME_MS((_s) * 1000))
 #define TIME_RELATIVE(_t)   (-(_t))
 
-__drv_functionClass(KDEFERRED_ROUTINE)
-__drv_maxIRQL(DISPATCH_LEVEL)
-__drv_minIRQL(DISPATCH_LEVEL)
-__drv_requiresIRQL(DISPATCH_LEVEL)
-__drv_sameIRQL
-static VOID
-ReceiverRingDpc(
-    IN  PKDPC               Dpc,
-    IN  PVOID               Context,
-    IN  PVOID               Argument1,
-    IN  PVOID               Argument2
-    )
-{
-    PXENVIF_RECEIVER_RING   Ring = Context;
-
-    UNREFERENCED_PARAMETER(Dpc);
-    UNREFERENCED_PARAMETER(Argument1);
-    UNREFERENCED_PARAMETER(Argument2);
-
-    ASSERT(Ring != NULL);
-
-    for (;;) {
-        BOOLEAN Retry;
-
-        __ReceiverRingAcquireLock(Ring);
-        Retry = ReceiverRingPoll(Ring);
-        __ReceiverRingReleaseLock(Ring);
-
-        if (!Retry) {
-            __ReceiverRingUnmask(Ring);
-            break;
-        }
-
-        if (__ReceiverRingDpcTimeout(Ring)) {
-            LARGE_INTEGER   Delay;
-
-            Delay.QuadPart = TIME_RELATIVE(TIME_US(100));
-
-            KeSetTimer(&Ring->Timer, Delay, &Ring->TimerDpc);
-            break;
-        }
-    }
-}
-
-KSERVICE_ROUTINE    ReceiverRingEvtchnCallback;
-
-BOOLEAN
-ReceiverRingEvtchnCallback(
-    IN  PKINTERRUPT             InterruptObject,
-    IN  PVOID                   Argument
-    )
-{
-    PXENVIF_RECEIVER_RING       Ring = Argument;
-    PXENVIF_RECEIVER            Receiver;
-    PXENVIF_FRONTEND            Frontend;
-
-    UNREFERENCED_PARAMETER(InterruptObject);
-
-    ASSERT(Ring != NULL);
-
-    Ring->Events++;
-
-    if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
-        Ring->Dpcs++;
-
-    Receiver = Ring->Receiver;
-    Frontend = Receiver->Frontend;
-
-    if (!FrontendIsSplit(Frontend))
-        TransmitterNotify(FrontendGetTransmitter(Frontend),
-                          Ring->Index);
-
-    return TRUE;
-}
-
 #define XENVIF_RECEIVER_WATCHDOG_PERIOD 30
 
 static NTSTATUS
@@ -2369,16 +2206,22 @@ ReceiverRingWatchdog(
             if (Ring->Shared->rsp_prod != rsp_prod &&
                 Ring->Front.rsp_cons == rsp_cons) {
                 PXENVIF_RECEIVER    Receiver;
+                PXENVIF_FRONTEND    Frontend;
 
                 Receiver = Ring->Receiver;
+                Frontend = Receiver->Frontend;
 
                 XENBUS_DEBUG(Trigger,
                              &Receiver->DebugInterface,
                              Ring->DebugCallback);
 
                 // Try to move things along
-                __ReceiverRingTrigger(Ring, TRUE);
-                __ReceiverRingSend(Ring, TRUE);
+                PollerTrigger(FrontendGetPoller(Frontend),
+                              Ring->Index,
+                              XENVIF_POLLER_EVENT_RECEIVE);
+                PollerSend(FrontendGetPoller(Frontend),
+                           Ring->Index,
+                           XENVIF_POLLER_EVENT_RECEIVE);
             }
 
             KeMemoryBarrier();
@@ -2426,10 +2269,6 @@ __ReceiverRingInitialize(
 
     InitializeListHead(&(*Ring)->PacketList);
 
-    KeInitializeDpc(&(*Ring)->Dpc, ReceiverRingDpc, *Ring);
-    KeInitializeTimer(&(*Ring)->Timer);
-    KeInitializeDpc(&(*Ring)->TimerDpc, ReceiverRingDpc, *Ring);
-
     status = RtlStringCbPrintfA(Name,
                                 sizeof (Name),
                                 "%s_receiver_packet",
@@ -2513,10 +2352,6 @@ fail4:
 fail3:
     Error("fail3\n");
 
-    RtlZeroMemory(&(*Ring)->TimerDpc, sizeof (KDPC));
-    RtlZeroMemory(&(*Ring)->Timer, sizeof (KTIMER));
-    RtlZeroMemory(&(*Ring)->Dpc, sizeof (KDPC));
-
     RtlZeroMemory(&(*Ring)->PacketList, sizeof (LIST_ENTRY));
 
     FrontendFreePath(Frontend, (*Ring)->Path);
@@ -2550,7 +2385,6 @@ __ReceiverRingConnect(
     PFN_NUMBER                  Pfn;
     CHAR                        Name[MAXNAMELEN];
     ULONG                       Index;
-    PROCESSOR_NUMBER            ProcNumber;
     NTSTATUS                    status;
 
     Receiver = Ring->Receiver;
@@ -2614,35 +2448,6 @@ __ReceiverRingConnect(
 
     ASSERT(!Ring->Connected);
 
-    Ring->Channel = XENBUS_EVTCHN(Open,
-                                  &Receiver->EvtchnInterface,
-                                  XENBUS_EVTCHN_TYPE_UNBOUND,
-                                  ReceiverRingEvtchnCallback,
-                                  Ring,
-                                  FrontendGetBackendDomain(Frontend),
-                                  TRUE);
-
-    status = STATUS_UNSUCCESSFUL;
-    if (Ring->Channel == NULL)
-        goto fail6;
-
-    status = KeGetProcessorNumberFromIndex(Ring->Index, &ProcNumber);
-    ASSERT(NT_SUCCESS(status));
-
-    KeSetTargetProcessorDpcEx(&Ring->Dpc, &ProcNumber);
-    KeSetTargetProcessorDpcEx(&Ring->TimerDpc, &ProcNumber);
-
-    (VOID) XENBUS_EVTCHN(Bind,
-                         &Receiver->EvtchnInterface,
-                         Ring->Channel,
-                         ProcNumber.Group,
-                         ProcNumber.Number);
-
-    XENBUS_EVTCHN(Unmask,
-                  &Receiver->EvtchnInterface,
-                  Ring->Channel,
-                  FALSE);
-
     Ring->Connected = TRUE;
 
     status = XENBUS_DEBUG(Register,
@@ -2652,25 +2457,15 @@ __ReceiverRingConnect(
                           Ring,
                           &Ring->DebugCallback);
     if (!NT_SUCCESS(status))
-        goto fail7;
+        goto fail6;
 
     return STATUS_SUCCESS;
 
-fail7:
-    Error("fail7\n");
-
-    Ring->Connected = FALSE;
-
-    XENBUS_EVTCHN(Close,
-                  &Receiver->EvtchnInterface,
-                  Ring->Channel);
-    Ring->Channel = NULL;
-
-    Ring->Events = 0;
-
 fail6:
     Error("fail6\n");
 
+    Ring->Connected = FALSE;
+
 fail5:
     Error("fail5\n");
 
@@ -2716,7 +2511,6 @@ __ReceiverRingStoreWrite(
 {
     PXENVIF_RECEIVER                Receiver;
     PXENVIF_FRONTEND                Frontend;
-    ULONG                           Port;
     PCHAR                           Path;
     NTSTATUS                        status;
 
@@ -2739,25 +2533,8 @@ __ReceiverRingStoreWrite(
     if (!NT_SUCCESS(status))
         goto fail1;
 
-    Port = XENBUS_EVTCHN(GetPort,
-                         &Receiver->EvtchnInterface,
-                         Ring->Channel);
-
-    status = XENBUS_STORE(Printf,
-                          &Receiver->StoreInterface,
-                          Transaction,
-                          Path,
-                          FrontendIsSplit(Frontend) ? "event-channel-rx" : 
"event-channel",
-                          "%u",
-                          Port);
-    if (!NT_SUCCESS(status))
-        goto fail2;
-
     return STATUS_SUCCESS;
 
-fail2:
-    Error("fail2\n");
-
 fail1:
     Error("fail1 (%08x)\n", status);
 
@@ -2792,8 +2569,6 @@ __ReceiverRingEnable(
 
     Ring->Enabled = TRUE;
 
-    (VOID) KeInsertQueueDpc(&Ring->Dpc, NULL, NULL);
-
     __ReceiverRingReleaseLock(Ring);
 
     Info("%s[%u]: <====\n",
@@ -2834,12 +2609,6 @@ __ReceiverRingDisable(
 
     __ReceiverRingReleaseLock(Ring);
 
-    //
-    // No new timers can be scheduled once Enabled goes to FALSE.
-    // Cancel any existing ones.
-    //
-    (VOID) KeCancelTimer(&Ring->Timer);
-
     Info("%s[%u]: <====\n",
          FrontendGetPath(Frontend),
          Ring->Index);
@@ -2861,14 +2630,6 @@ __ReceiverRingDisconnect(
     ASSERT(Ring->Connected);
     Ring->Connected = FALSE;
 
-    XENBUS_EVTCHN(Close,
-                  &Receiver->EvtchnInterface,
-                  Ring->Channel);
-    Ring->Channel = NULL;
-
-    Ring->Events = 0;
-    Ring->Dpcs = 0;
-
     ASSERT3U(Ring->ResponsesProcessed, ==, Ring->RequestsPushed);
     ASSERT3U(Ring->RequestsPushed, ==, Ring->RequestsPosted);
 
@@ -2913,9 +2674,6 @@ __ReceiverRingTeardown(
     Frontend = Receiver->Frontend;
 
     RtlZeroMemory(&Ring->Hash, sizeof (XENVIF_RECEIVER_HASH));
-    RtlZeroMemory(&Ring->TimerDpc, sizeof (KDPC));
-    RtlZeroMemory(&Ring->Timer, sizeof (KTIMER));
-    RtlZeroMemory(&Ring->Dpc, sizeof (KDPC));
 
     Ring->BackfillSize = 0;
     Ring->OffloadOptions.Value = 0;
@@ -3085,9 +2843,6 @@ ReceiverInitialize(
     FdoGetGnttabInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
                           &(*Receiver)->GnttabInterface);
 
-    FdoGetEvtchnInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
-                          &(*Receiver)->EvtchnInterface);
-
     (*Receiver)->Frontend = Frontend;
 
     status = XENBUS_CACHE(Acquire, &(*Receiver)->CacheInterface);
@@ -3140,9 +2895,6 @@ fail2:
 
     (*Receiver)->Frontend = NULL;
 
-    RtlZeroMemory(&(*Receiver)->EvtchnInterface,
-                  sizeof (XENBUS_EVTCHN_INTERFACE));
-
     RtlZeroMemory(&(*Receiver)->GnttabInterface,
                   sizeof (XENBUS_GNTTAB_INTERFACE));
 
@@ -3194,13 +2946,9 @@ ReceiverConnect(
     if (!NT_SUCCESS(status))
         goto fail2;
 
-    status = XENBUS_EVTCHN(Acquire, &Receiver->EvtchnInterface);
-    if (!NT_SUCCESS(status))
-        goto fail3;
-
     status = XENBUS_GNTTAB(Acquire, &Receiver->GnttabInterface);
     if (!NT_SUCCESS(status))
-        goto fail4;
+        goto fail3;
 
     Index = 0;
     while (Index < (LONG)FrontendGetNumQueues(Frontend)) {
@@ -3208,7 +2956,7 @@ ReceiverConnect(
 
         status = __ReceiverRingConnect(Ring);
         if (!NT_SUCCESS(status))
-            goto fail5;
+            goto fail4;
 
         Index++;
     }    
@@ -3220,18 +2968,18 @@ ReceiverConnect(
                           Receiver,
                           &Receiver->DebugCallback);
     if (!NT_SUCCESS(status))
-        goto fail6;
+        goto fail5;
 
     Trace("<====\n");
     return STATUS_SUCCESS;
 
-fail6:
-    Error("fail6\n");
+fail5:
+    Error("fail5\n");
 
     Index = FrontendGetNumQueues(Frontend);
 
-fail5:
-    Error("fail5\n");
+fail4:
+    Error("fail4\n");
 
     while (--Index >= 0) {
         PXENVIF_RECEIVER_RING   Ring = Receiver->Ring[Index];
@@ -3241,11 +2989,6 @@ fail5:
 
     XENBUS_GNTTAB(Release, &Receiver->GnttabInterface);
 
-fail4:
-    Error("fail4\n");
-
-    XENBUS_EVTCHN(Release, &Receiver->EvtchnInterface);
-
 fail3:
     Error("fail3\n");
 
@@ -3485,6 +3228,34 @@ fail1:
     return status;
 }
 
+BOOLEAN
+ReceiverPoll(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  ULONG               Index
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    ULONG                   NumQueues;
+    PXENVIF_RECEIVER_RING   Ring;
+    BOOLEAN                 Retry;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+    Frontend = Receiver->Frontend;
+
+    NumQueues = FrontendGetNumQueues(Frontend);
+    if (Index >= NumQueues)
+        return FALSE;
+
+    Ring = Receiver->Ring[Index];
+
+    __ReceiverRingAcquireLock(Ring);
+    Retry = ReceiverRingPoll(Ring);
+    __ReceiverRingReleaseLock(Ring);
+
+    return Retry;
+}
+
 VOID
 ReceiverDisable(
     IN  PXENVIF_RECEIVER    Receiver
@@ -3533,8 +3304,6 @@ ReceiverDisconnect(
 
     XENBUS_GNTTAB(Release, &Receiver->GnttabInterface);
 
-    XENBUS_EVTCHN(Release, &Receiver->EvtchnInterface);
-
     XENBUS_STORE(Release, &Receiver->StoreInterface);
 
     XENBUS_DEBUG(Release, &Receiver->DebugInterface);
@@ -3552,9 +3321,6 @@ ReceiverTeardown(
 
     Frontend = Receiver->Frontend;
 
-    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
-    KeFlushQueuedDpcs();
-
     ASSERT3U(Receiver->Returned, ==, Receiver->Loaned);
     Receiver->Loaned = 0;
     Receiver->Returned = 0;
@@ -3574,9 +3340,6 @@ ReceiverTeardown(
 
     Receiver->Frontend = NULL;
 
-    RtlZeroMemory(&Receiver->EvtchnInterface,
-                  sizeof (XENBUS_EVTCHN_INTERFACE));
-
     RtlZeroMemory(&Receiver->GnttabInterface,
                   sizeof (XENBUS_GNTTAB_INTERFACE));
 
@@ -3753,32 +3516,6 @@ ReceiverWaitForPackets(
     Trace("%s: <====\n", FrontendGetPath(Frontend));
 }
 
-VOID
-ReceiverTrigger(
-    IN  PXENVIF_RECEIVER    Receiver,
-    IN  ULONG               Index
-    )
-{
-    PXENVIF_RECEIVER_RING   Ring;
-
-    Ring = Receiver->Ring[Index];
-
-    __ReceiverRingTrigger(Ring, FALSE);
-}
-
-VOID
-ReceiverSend(
-    IN  PXENVIF_RECEIVER    Receiver,
-    IN  ULONG               Index
-    )
-{
-    PXENVIF_RECEIVER_RING   Ring;
-
-    Ring = Receiver->Ring[Index];
-
-    __ReceiverRingSend(Ring, FALSE);
-}
-
 NTSTATUS
 ReceiverSetHashAlgorithm(
     IN  PXENVIF_RECEIVER                Receiver,
diff --git a/src/xenvif/receiver.h b/src/xenvif/receiver.h
index 7846f0b..e1b7a88 100644
--- a/src/xenvif/receiver.h
+++ b/src/xenvif/receiver.h
@@ -62,6 +62,12 @@ ReceiverEnable(
     IN  PXENVIF_RECEIVER    Receiver
     );
 
+extern BOOLEAN
+ReceiverPoll(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  ULONG               Index
+    );
+
 extern VOID
 ReceiverDisable(
     IN  PXENVIF_RECEIVER    Receiver
diff --git a/src/xenvif/transmitter.c b/src/xenvif/transmitter.c
index 3ab3cbd..eed0a0f 100644
--- a/src/xenvif/transmitter.c
+++ b/src/xenvif/transmitter.c
@@ -43,7 +43,6 @@
 #include <cache_interface.h>
 #include <gnttab_interface.h>
 #include <range_set_interface.h>
-#include <evtchn_interface.h>
 
 #include "pdo.h"
 #include "frontend.h"
@@ -179,12 +178,6 @@ typedef struct _XENVIF_TRANSMITTER_RING {
     netif_tx_front_ring_t           Front;
     netif_tx_sring_t                *Shared;
     PXENBUS_GNTTAB_ENTRY            Entry;
-    PXENBUS_EVTCHN_CHANNEL          Channel;
-    KDPC                            Dpc;
-    ULONG                           Dpcs;
-    KTIMER                          Timer;
-    KDPC                            TimerDpc;
-    ULONG                           Events;
     BOOLEAN                         Connected;
     BOOLEAN                         Enabled;
     BOOLEAN                         Stopped;
@@ -215,7 +208,6 @@ struct _XENVIF_TRANSMITTER {
     XENBUS_CACHE_INTERFACE      CacheInterface;
     XENBUS_GNTTAB_INTERFACE     GnttabInterface;
     XENBUS_RANGE_SET_INTERFACE  RangeSetInterface;
-    XENBUS_EVTCHN_INTERFACE     EvtchnInterface;
     PXENVIF_TRANSMITTER_RING    *Ring;
     BOOLEAN                     MulticastControl;
     ULONG                       DisableIpVersion4Gso;
@@ -770,15 +762,6 @@ TransmitterRingDebugCallback(
                  Ring->PacketsUnprepared,
                  Ring->PacketsSent,
                  Ring->PacketsCompleted);
-
-    if (FrontendIsSplit(Frontend)) {
-        // Dump event channel
-        XENBUS_DEBUG(Printf,
-                     &Transmitter->DebugInterface,
-                     "Events = %lu Dpcs = %lu\n",
-                     Ring->Events,
-                     Ring->Dpcs);
-    }
 }
 
 static BOOLEAN
@@ -2796,64 +2779,17 @@ done:
 }
 
 static FORCEINLINE VOID
-__TransmitterRingTrigger(
-    IN  PXENVIF_TRANSMITTER_RING    Ring
-    )
-{
-    PXENVIF_TRANSMITTER             Transmitter;
-    PXENVIF_FRONTEND                Frontend;
-
-    Transmitter = Ring->Transmitter;
-    Frontend = Transmitter->Frontend;
-
-    if (!Ring->Connected)
-        return;
-
-    if (FrontendIsSplit(Frontend)) {
-        ASSERT(Ring->Channel != NULL);
-
-        (VOID) XENBUS_EVTCHN(Trigger,
-                             &Transmitter->EvtchnInterface,
-                             Ring->Channel);
-    } else {
-        ReceiverTrigger(FrontendGetReceiver(Frontend),
-                        Ring->Index);
-    }
-}
-
-static FORCEINLINE VOID
-__TransmitterRingSend(
+__TransmitterRingPushRequests(
     IN  PXENVIF_TRANSMITTER_RING    Ring
     )
 {
     PXENVIF_TRANSMITTER             Transmitter;
     PXENVIF_FRONTEND                Frontend;
+    BOOLEAN                         Notify;
 
     Transmitter = Ring->Transmitter;
     Frontend = Transmitter->Frontend;
 
-    if (!Ring->Connected)
-        return;
-
-    if (FrontendIsSplit(Frontend)) {
-        ASSERT(Ring->Channel != NULL);
-
-        (VOID) XENBUS_EVTCHN(Send,
-                             &Transmitter->EvtchnInterface,
-                             Ring->Channel);
-    } else {
-        ReceiverSend(FrontendGetReceiver(Frontend),
-                     Ring->Index);
-    }
-}
-
-static FORCEINLINE VOID
-__TransmitterRingPushRequests(
-    IN  PXENVIF_TRANSMITTER_RING    Ring
-    )
-{
-    BOOLEAN                         Notify;
-
     if (Ring->RequestsPosted == Ring->RequestsPushed)
         return;
 
@@ -2866,7 +2802,9 @@ __TransmitterRingPushRequests(
 #pragma warning (pop)
 
     if (Notify)
-        __TransmitterRingSend(Ring);
+        PollerSend(FrontendGetPoller(Frontend),
+                   Ring->Index,
+                   XENVIF_POLLER_EVENT_TRANSMIT);
 
     Ring->RequestsPushed = Ring->RequestsPosted;
 }
@@ -3220,130 +3158,11 @@ TransmitterRingReleaseLock(
     __TransmitterRingReleaseLock(Ring);
 }
 
-static FORCEINLINE VOID
-__TransmitterRingUnmask(
-    IN  PXENVIF_TRANSMITTER_RING    Ring
-    )
-{
-    PXENVIF_TRANSMITTER             Transmitter;
-    PXENVIF_FRONTEND                Frontend;
-
-    Transmitter = Ring->Transmitter;
-    Frontend = Transmitter->Frontend;
-
-    if (!Ring->Connected || !FrontendIsSplit(Frontend))
-        return;
-
-    XENBUS_EVTCHN(Unmask,
-                  &Transmitter->EvtchnInterface,
-                  Ring->Channel,
-                  FALSE);
-}
-
-static FORCEINLINE BOOLEAN
-__TransmitterRingDpcTimeout(
-    IN  PXENVIF_TRANSMITTER_RING    Ring
-    )
-{
-    KDPC_WATCHDOG_INFORMATION       Watchdog;
-    NTSTATUS                        status;
-
-    UNREFERENCED_PARAMETER(Ring);
-
-    RtlZeroMemory(&Watchdog, sizeof (Watchdog));
-
-    status = KeQueryDpcWatchdogInformation(&Watchdog);
-    ASSERT(NT_SUCCESS(status));
-
-    if (Watchdog.DpcTimeLimit == 0 ||
-        Watchdog.DpcWatchdogLimit == 0)
-        return FALSE;
-
-    if (Watchdog.DpcTimeCount > (Watchdog.DpcTimeLimit / 2) &&
-        Watchdog.DpcWatchdogCount > (Watchdog.DpcWatchdogLimit / 2))
-        return FALSE;
-
-    return TRUE;
-}
-
 #define TIME_US(_us)        ((_us) * 10)
 #define TIME_MS(_ms)        (TIME_US((_ms) * 1000))
 #define TIME_S(_s)          (TIME_MS((_s) * 1000))
 #define TIME_RELATIVE(_t)   (-(_t))
 
-__drv_functionClass(KDEFERRED_ROUTINE)
-__drv_maxIRQL(DISPATCH_LEVEL)
-__drv_minIRQL(DISPATCH_LEVEL)
-__drv_requiresIRQL(DISPATCH_LEVEL)
-__drv_sameIRQL
-static VOID
-TransmitterRingDpc(
-    IN  PKDPC                   Dpc,
-    IN  PVOID                   Context,
-    IN  PVOID                   Argument1,
-    IN  PVOID                   Argument2
-    )
-{
-    PXENVIF_TRANSMITTER_RING    Ring = Context;
-
-    UNREFERENCED_PARAMETER(Dpc);
-    UNREFERENCED_PARAMETER(Argument1);
-    UNREFERENCED_PARAMETER(Argument2);
-
-    ASSERT(Ring != NULL);
-
-    for (;;) {
-        BOOLEAN Retry;
-
-        __TransmitterRingAcquireLock(Ring);
-        Retry = TransmitterRingPoll(Ring);
-        __TransmitterRingReleaseLock(Ring);
-
-        if (!Retry) {
-            __TransmitterRingUnmask(Ring);
-           break;
-        }
-
-        if (__TransmitterRingDpcTimeout(Ring)) {
-            LARGE_INTEGER   Delay;
-
-            Delay.QuadPart = TIME_RELATIVE(TIME_US(100));
-
-            KeSetTimer(&Ring->Timer, Delay, &Ring->TimerDpc);
-            break;
-        }
-    }
-}
-
-KSERVICE_ROUTINE    TransmitterRingEvtchnCallback;
-
-BOOLEAN
-TransmitterRingEvtchnCallback(
-    IN  PKINTERRUPT             InterruptObject,
-    IN  PVOID                   Argument
-    )
-{
-    PXENVIF_TRANSMITTER_RING    Ring = Argument;
-    PXENVIF_TRANSMITTER         Transmitter;
-    PXENVIF_FRONTEND            Frontend;
-
-    UNREFERENCED_PARAMETER(InterruptObject);
-
-    ASSERT(Ring != NULL);
-
-    Transmitter = Ring->Transmitter;
-    Frontend = Transmitter->Frontend;
-
-    ASSERT(FrontendIsSplit(Frontend));
-
-    Ring->Events++;
-
-    if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
-        Ring->Dpcs++;
-
-    return TRUE;
-}
-
 #define XENVIF_TRANSMITTER_WATCHDOG_PERIOD  30
 
 static NTSTATUS
@@ -3402,16 +3221,22 @@ TransmitterRingWatchdog(
             if (Ring->PacketsQueued == PacketsQueued &&
                 Ring->PacketsCompleted != PacketsQueued) {
                 PXENVIF_TRANSMITTER Transmitter;
+                PXENVIF_FRONTEND    Frontend;
 
                 Transmitter = Ring->Transmitter;
+                Frontend = Transmitter->Frontend;
 
                 XENBUS_DEBUG(Trigger,
                              &Transmitter->DebugInterface,
                              Ring->DebugCallback);
 
                 // Try to move things along
-                __TransmitterRingTrigger(Ring);
-                __TransmitterRingSend(Ring);
+                PollerTrigger(FrontendGetPoller(Frontend),
+                              Ring->Index,
+                              XENVIF_POLLER_EVENT_TRANSMIT);
+                PollerSend(FrontendGetPoller(Frontend),
+                           Ring->Index,
+                           XENVIF_POLLER_EVENT_TRANSMIT);
             }
 
             PacketsQueued = Ring->PacketsQueued;
@@ -3456,10 +3281,6 @@ __TransmitterRingInitialize(
     InitializeListHead(&(*Ring)->RequestQueue);
     InitializeListHead(&(*Ring)->PacketComplete);
 
-    KeInitializeDpc(&(*Ring)->Dpc, TransmitterRingDpc, *Ring);
-    KeInitializeTimer(&(*Ring)->Timer);
-    KeInitializeDpc(&(*Ring)->TimerDpc, TransmitterRingDpc, *Ring);
-
     status = RtlStringCbPrintfA(Name,
                                 sizeof (Name),
                                 "%s_transmitter_buffer",
@@ -3661,8 +3482,6 @@ fail4:
 fail3:
     Error("fail3\n");
 
-    RtlZeroMemory(&(*Ring)->Dpc, sizeof (KDPC));
-
     RtlZeroMemory(&(*Ring)->PacketComplete, sizeof (LIST_ENTRY));
     RtlZeroMemory(&(*Ring)->RequestQueue, sizeof (LIST_ENTRY));
     RtlZeroMemory(&(*Ring)->PacketQueue, sizeof (LIST_ENTRY));
@@ -3696,7 +3515,6 @@ __TransmitterRingConnect(
     PFN_NUMBER                      Pfn;
     CHAR                            Name[MAXNAMELEN];
     ULONG                           Index;
-    PROCESSOR_NUMBER                ProcNumber;
     NTSTATUS                        status;
 
     ASSERT(!Ring->Connected);
@@ -3762,37 +3580,6 @@ __TransmitterRingConnect(
 
     ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
 
-    if (FrontendIsSplit(Frontend)) {
-        Ring->Channel = XENBUS_EVTCHN(Open,
-                                      &Transmitter->EvtchnInterface,
-                                      XENBUS_EVTCHN_TYPE_UNBOUND,
-                                      TransmitterRingEvtchnCallback,
-                                      Ring,
-                                      FrontendGetBackendDomain(Frontend),
-                                      TRUE);
-
-        status = STATUS_UNSUCCESSFUL;
-        if (Ring->Channel == NULL)
-            goto fail6;
-
-        status = KeGetProcessorNumberFromIndex(Ring->Index, &ProcNumber);
-        ASSERT(NT_SUCCESS(status));
-
-        KeSetTargetProcessorDpcEx(&Ring->Dpc, &ProcNumber);
-        KeSetTargetProcessorDpcEx(&Ring->TimerDpc, &ProcNumber);
-
-        (VOID) XENBUS_EVTCHN(Bind,
-                             &Transmitter->EvtchnInterface,
-                             Ring->Channel,
-                             ProcNumber.Group,
-                             ProcNumber.Number);
-
-        XENBUS_EVTCHN(Unmask,
-                      &Transmitter->EvtchnInterface,
-                      Ring->Channel,
-                      FALSE);
-    }
-
     status = XENBUS_DEBUG(Register,
                           &Transmitter->DebugInterface,
                           Name,
@@ -3800,22 +3587,12 @@ __TransmitterRingConnect(
                           Ring,
                           &Ring->DebugCallback);
     if (!NT_SUCCESS(status))
-        goto fail7;
+        goto fail6;
 
     Ring->Connected = TRUE;
 
     return STATUS_SUCCESS;
 
-fail7:
-    Error("fail7\n");
-
-    XENBUS_EVTCHN(Close,
-                  &Transmitter->EvtchnInterface,
-                  Ring->Channel);
-    Ring->Channel = NULL;
-
-    Ring->Events = 0;
-
 fail6:
     Error("fail6\n");
 
@@ -3864,7 +3641,6 @@ __TransmitterRingStoreWrite(
 {
     PXENVIF_TRANSMITTER             Transmitter;
     PXENVIF_FRONTEND                Frontend;
-    ULONG                           Port;
     PCHAR                           Path;
     NTSTATUS                        status;
 
@@ -3887,29 +3663,8 @@ __TransmitterRingStoreWrite(
     if (!NT_SUCCESS(status))
         goto fail1;
 
-    if (!FrontendIsSplit(Frontend))
-        goto done;
-
-    Port = XENBUS_EVTCHN(GetPort,
-                         &Transmitter->EvtchnInterface,
-                         Ring->Channel);
-
-    status = XENBUS_STORE(Printf,
-                          &Transmitter->StoreInterface,
-                          Transaction,
-                          Path,
-                          "event-channel-tx",
-                          "%u",
-                          Port);
-    if (!NT_SUCCESS(status))
-        goto fail2;
-
-done:
     return STATUS_SUCCESS;
 
-fail2:
-    Error("fail2\n");
-
 fail1:
     Error("fail1 (%08x)\n", status);
 
@@ -3936,8 +3691,6 @@ __TransmitterRingEnable(
     ASSERT(!Ring->Enabled);
     Ring->Enabled = TRUE;
 
-    KeInsertQueueDpc(&Ring->Dpc, NULL, NULL);
-
     __TransmitterRingReleaseLock(Ring);
 
     Info("%s[%u]: <====\n",
@@ -4017,7 +3770,9 @@ __TransmitterRingDisable(
         ASSERT(Attempt < 100);
 
         // Try to move things along
-        __TransmitterRingSend(Ring);
+        PollerSend(FrontendGetPoller(Frontend),
+                   Ring->Index,
+                   XENVIF_POLLER_EVENT_TRANSMIT);
         (VOID) TransmitterRingPoll(Ring);
 
         if (State != XenbusStateConnected)
@@ -4035,12 +3790,6 @@ __TransmitterRingDisable(
 
     __TransmitterRingReleaseLock(Ring);
 
-    //
-    // No new timers can be scheduled once Enabled goes to FALSE.
-    // Cancel any existing ones.
-    //
-    (VOID) KeCancelTimer(&Ring->Timer);
-
     Info("%s[%u]: <====\n",
          FrontendGetPath(Frontend),
          Ring->Index);
@@ -4060,17 +3809,6 @@ __TransmitterRingDisconnect(
     Transmitter = Ring->Transmitter;
     Frontend = Transmitter->Frontend;
 
-    if (Ring->Channel != NULL) {
-        XENBUS_EVTCHN(Close,
-                      &Transmitter->EvtchnInterface,
-                      Ring->Channel);
-        Ring->Channel = NULL;
-
-        Ring->Events = 0;
-    }
-
-    Ring->Dpcs = 0;
-
     ASSERT3U(Ring->ResponsesProcessed, ==, Ring->RequestsPushed);
     ASSERT3U(Ring->RequestsPushed, ==, Ring->RequestsPosted);
 
@@ -4114,12 +3852,6 @@ __TransmitterRingTeardown(
     Transmitter = Ring->Transmitter;
     Frontend = Transmitter->Frontend;
 
-    Ring->Dpcs = 0;
-
-    RtlZeroMemory(&Ring->TimerDpc, sizeof (KDPC));
-    RtlZeroMemory(&Ring->Timer, sizeof (KTIMER));
-    RtlZeroMemory(&Ring->Dpc, sizeof (KDPC));
-
     ASSERT3U(Ring->PacketsCompleted, ==, Ring->PacketsSent);
     ASSERT3U(Ring->PacketsSent, ==, Ring->PacketsPrepared - 
Ring->PacketsUnprepared);
     ASSERT3U(Ring->PacketsPrepared, ==, Ring->PacketsCopied + 
Ring->PacketsGranted + Ring->PacketsFaked);
@@ -4545,9 +4277,6 @@ TransmitterInitialize(
     FdoGetGnttabInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
                           &(*Transmitter)->GnttabInterface);
 
-    FdoGetEvtchnInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
-                          &(*Transmitter)->EvtchnInterface);
-
     (*Transmitter)->Frontend = Frontend;
     KeInitializeSpinLock(&(*Transmitter)->Lock);
 
@@ -4700,13 +4429,9 @@ TransmitterConnect(
     if (!NT_SUCCESS(status))
         goto fail2;
 
-    status = XENBUS_EVTCHN(Acquire, &Transmitter->EvtchnInterface);
-    if (!NT_SUCCESS(status))
-        goto fail3;
-
     status = XENBUS_GNTTAB(Acquire, &Transmitter->GnttabInterface);
     if (!NT_SUCCESS(status))
-        goto fail4;
+        goto fail3;
 
     if (Transmitter->DisableMulticastControl == 0) {
         status = XENBUS_STORE(Read,
@@ -4730,7 +4455,7 @@ TransmitterConnect(
 
         status = __TransmitterRingConnect(Ring);
         if (!NT_SUCCESS(status))
-            goto fail5;
+            goto fail4;
 
         Index++;
     }    
@@ -4742,18 +4467,18 @@ TransmitterConnect(
                           Transmitter,
                           &Transmitter->DebugCallback);
     if (!NT_SUCCESS(status))
-        goto fail6;
+        goto fail5;
 
     Trace("<====\n");
     return STATUS_SUCCESS;
 
-fail6:
-    Error("fail6\n");
+fail5:
+    Error("fail5\n");
 
     Index = FrontendGetNumQueues(Frontend);
 
-fail5:
-    Error("fail5\n");
+fail4:
+    Error("fail4\n");
 
     while (--Index >= 0) {
         PXENVIF_TRANSMITTER_RING    Ring;
@@ -4767,11 +4492,6 @@ fail5:
 
     XENBUS_GNTTAB(Release, &Transmitter->GnttabInterface);
 
-fail4:
-    Error("fail4\n");
-
-    XENBUS_EVTCHN(Release, &Transmitter->EvtchnInterface);
-
 fail3:
     Error("fail3\n");
 
@@ -4908,6 +4628,34 @@ TransmitterEnable(
     return STATUS_SUCCESS;
 }
 
+BOOLEAN
+TransmitterPoll(
+    IN  PXENVIF_TRANSMITTER     Transmitter,
+    IN  ULONG                   Index
+    )
+{
+    PXENVIF_FRONTEND            Frontend;
+    ULONG                       NumQueues;
+    PXENVIF_TRANSMITTER_RING    Ring;
+    BOOLEAN                     Retry;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+    Frontend = Transmitter->Frontend;
+
+    NumQueues = FrontendGetNumQueues(Frontend);
+    if (Index >= NumQueues)
+        return FALSE;
+
+    Ring = Transmitter->Ring[Index];
+
+    __TransmitterRingAcquireLock(Ring);
+    Retry = TransmitterRingPoll(Ring);
+    __TransmitterRingReleaseLock(Ring);
+
+    return Retry;
+}
+
 VOID
 TransmitterDisable(
     IN  PXENVIF_TRANSMITTER Transmitter
@@ -4958,8 +4706,6 @@ TransmitterDisconnect(
 
     XENBUS_GNTTAB(Release, &Transmitter->GnttabInterface);
 
-    XENBUS_EVTCHN(Release, &Transmitter->EvtchnInterface);
-
     XENBUS_STORE(Release, &Transmitter->StoreInterface);
 
     XENBUS_DEBUG(Release, &Transmitter->DebugInterface);
@@ -4978,7 +4724,6 @@ TransmitterTeardown(
     Frontend = Transmitter->Frontend;
 
     ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
-    KeFlushQueuedDpcs();
 
     Index = FrontendGetMaxQueues(Frontend);
     while (--Index >= 0) {
@@ -5020,9 +4765,6 @@ TransmitterTeardown(
     RtlZeroMemory(&Transmitter->DebugInterface,
                   sizeof (XENBUS_DEBUG_INTERFACE));
 
-    RtlZeroMemory(&Transmitter->EvtchnInterface,
-                  sizeof (XENBUS_EVTCHN_INTERFACE));
-
     Transmitter->DisableIpVersion4Gso = 0;
     Transmitter->DisableIpVersion6Gso = 0;
     Transmitter->AlwaysCopy = 0;
@@ -5299,25 +5041,6 @@ TransmitterQueryRingSize(
 }
 
 VOID
-TransmitterNotify(
-    IN  PXENVIF_TRANSMITTER     Transmitter,
-    IN  ULONG                   Index
-    )
-{
-    PXENVIF_FRONTEND            Frontend;
-    PXENVIF_TRANSMITTER_RING    Ring;
-
-    Frontend = Transmitter->Frontend;
-
-    ASSERT(!FrontendIsSplit(Frontend));
-
-    Ring = Transmitter->Ring[Index];
-
-    if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
-        Ring->Dpcs++;
-}
-
-VOID
 TransmitterQueryOffloadOptions(
     IN  PXENVIF_TRANSMITTER         Transmitter,
     OUT PXENVIF_VIF_OFFLOAD_OPTIONS Options
diff --git a/src/xenvif/transmitter.h b/src/xenvif/transmitter.h
index d44f77e..2446220 100644
--- a/src/xenvif/transmitter.h
+++ b/src/xenvif/transmitter.h
@@ -64,6 +64,12 @@ TransmitterEnable(
     IN  PXENVIF_TRANSMITTER Transmitter
     );
 
+extern BOOLEAN
+TransmitterPoll(
+    IN  PXENVIF_TRANSMITTER     Transmitter,
+    IN  ULONG                   Index
+    );
+
 extern VOID
 TransmitterDisable(
     IN  PXENVIF_TRANSMITTER Transmitter
-- 
2.5.3


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.