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;
Ring->Dpcs);
}
-static DECLSPEC_NOINLINE VOID
+static DECLSPEC_NOINLINE BOOLEAN
ReceiverRingPoll(
IN PXENVIF_RECEIVER_RING Ring
)
PXENVIF_RECEIVER Receiver;
PXENVIF_FRONTEND Frontend;
-
- if (!(Ring->Enabled))
- return;
+ BOOLEAN Retry;
Receiver = Ring->Receiver;
Frontend = Receiver->Frontend;
+ Retry = FALSE;
+
+ if (!Ring->Enabled)
+ goto done;
for (;;) {
BOOLEAN Error;
KeMemoryBarrier();
- if (rsp_cons == rsp_prod)
+ if (rsp_cons == rsp_prod || Retry)
break;
- while (rsp_cons != rsp_prod) {
+ while (rsp_cons != rsp_prod && !Retry) {
netif_rx_response_t *rsp;
uint16_t id;
PXENVIF_RECEIVER_FRAGMENT Fragment;
PMDL Mdl;
- RING_IDX req_prod;
rsp = RING_GET_RESPONSE(&Ring->Front, rsp_cons);
InsertTailList(&Ring->PacketList, &Packet->ListEntry);
}
+ if (rsp_cons - Ring->Front.rsp_cons > XENVIF_RECEIVER_BATCH(Ring))
+ Retry = TRUE;
+
Error = FALSE;
Info = 0;
MaximumSegmentSize = 0;
flags = 0;
TailMdl = NULL;
}
-
- KeMemoryBarrier();
-
- req_prod = Ring->Front.req_prod_pvt;
-
- if (req_prod - rsp_cons < XENVIF_RECEIVER_BATCH(Ring) &&
- !__ReceiverRingIsStopped(Ring)) {
- Ring->Front.rsp_cons = rsp_cons;
- ReceiverRingFill(Ring);
- }
}
ASSERT(!Error);
ASSERT(!Extra);
if (!__ReceiverRingIsStopped(Ring))
ReceiverRingFill(Ring);
+done:
+ return Retry;
+
#undef XENVIF_RECEIVER_BATCH
}
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)
ASSERT(Ring != NULL);
- Ring->Dpcs++;
+ for (;;) {
+ BOOLEAN Retry;
- __ReceiverRingAcquireLock(Ring);
+ __ReceiverRingAcquireLock(Ring);
+ Retry = ReceiverRingPoll(Ring);
+ __ReceiverRingReleaseLock(Ring);
+
+ if (!Retry) {
+ __ReceiverRingUnmask(Ring);
+ break;
+ }
- if (Ring->Enabled)
- ReceiverRingPoll(Ring);
+ if (__ReceiverRingDpcTimeout(Ring)) {
+ LARGE_INTEGER Delay;
- __ReceiverRingReleaseLock(Ring);
- __ReceiverRingUnmask(Ring);
+ Delay.QuadPart = TIME_RELATIVE(TIME_US(100));
+
+ KeSetTimer(&Ring->Timer, Delay, &Ring->TimerDpc);
+ break;
+ }
+ }
}
KSERVICE_ROUTINE ReceiverRingEvtchnCallback;
Ring->Events++;
- (VOID) KeInsertQueueDpc(&Ring->Dpc, NULL, NULL);
+ if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
+ Ring->Dpcs++;
Receiver = Ring->Receiver;
Frontend = Receiver->Frontend;
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))
-
#define XENVIF_RECEIVER_WATCHDOG_PERIOD 30
static NTSTATUS
InitializeListHead(&(*Ring)->PacketList);
KeInitializeDpc(&(*Ring)->Dpc, ReceiverRingDpc, *Ring);
+ KeInitializeTimer(&(*Ring)->Timer);
+ KeInitializeDpc(&(*Ring)->TimerDpc, ReceiverRingDpc, *Ring);
status = ThreadCreate(ReceiverRingWatchdog,
*Ring,
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));
ASSERT(NT_SUCCESS(status));
KeSetTargetProcessorDpcEx(&Ring->Dpc, &ProcNumber);
+ KeSetTargetProcessorDpcEx(&Ring->TimerDpc, &ProcNumber);
(VOID) XENBUS_EVTCHN(Bind,
&Receiver->EvtchnInterface,
Receiver = Ring->Receiver;
Frontend = Receiver->Frontend;
+ RtlZeroMemory(&Ring->TimerDpc, sizeof (KDPC));
+ RtlZeroMemory(&Ring->Timer, sizeof (KTIMER));
RtlZeroMemory(&Ring->Dpc, sizeof (KDPC));
Ring->BackfillSize = 0;
PXENBUS_EVTCHN_CHANNEL Channel;
KDPC Dpc;
ULONG Dpcs;
+ KTIMER Timer;
+ KDPC TimerDpc;
ULONG Events;
BOOLEAN Connected;
BOOLEAN Enabled;
Ring->PacketsCompleted++;
}
-static DECLSPEC_NOINLINE VOID
+static DECLSPEC_NOINLINE BOOLEAN
TransmitterRingPoll(
IN PXENVIF_TRANSMITTER_RING Ring
)
PXENVIF_TRANSMITTER Transmitter;
PXENVIF_FRONTEND Frontend;
+ BOOLEAN Retry;
Transmitter = Ring->Transmitter;
Frontend = Transmitter->Frontend;
+ Retry = FALSE;
+
+ if (!Ring->Enabled)
+ goto done;
for (;;) {
RING_IDX rsp_prod;
RING_IDX rsp_cons;
- ULONG Delta;
KeMemoryBarrier();
KeMemoryBarrier();
- if (rsp_cons == rsp_prod)
+ if (rsp_cons == rsp_prod || Retry)
break;
- while (rsp_cons != rsp_prod) {
+ while (rsp_cons != rsp_prod && !Retry) {
netif_tx_response_t *rsp;
uint16_t id;
PXENVIF_TRANSMITTER_FRAGMENT Fragment;
Fragment->Extra = FALSE;
__TransmitterPutFragment(Ring, Fragment);
- if (Packet == NULL) {
- RtlZeroMemory(rsp, sizeof (netif_tx_response_t));
+ if (Packet == NULL)
continue;
- }
--Packet->Reference;
}
}
- RtlZeroMemory(rsp, sizeof (netif_tx_response_t));
-
if (Packet->Reference != 0)
continue;
Packet->Completion.Status = XENVIF_TRANSMITTER_PACKET_OK;
__TransmitterRingCompletePacket(Ring, Packet);
+
+ if (rsp_cons - Ring->Front.rsp_cons > XENVIF_TRANSMITTER_BATCH(Ring))
+ Retry = TRUE;
}
KeMemoryBarrier();
Ring->Front.rsp_cons = rsp_cons;
-
- Delta = Ring->Front.req_prod_pvt - rsp_cons;
- Delta = __min(Delta, XENVIF_TRANSMITTER_BATCH(Ring));
- Delta = __max(Delta, 1);
-
- Ring->Shared->rsp_event = rsp_cons + Delta;
+ Ring->Shared->rsp_event = rsp_cons + 1;
}
+done:
+ return Retry;
+
#undef XENVIF_TRANSMITTER_BATCH
}
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)
ASSERT(Ring != NULL);
- Ring->Dpcs++;
+ for (;;) {
+ BOOLEAN Retry;
- __TransmitterRingAcquireLock(Ring);
+ __TransmitterRingAcquireLock(Ring);
+ Retry = TransmitterRingPoll(Ring);
+ __TransmitterRingReleaseLock(Ring);
- if (Ring->Enabled)
- TransmitterRingPoll(Ring);
+ if (!Retry) {
+ __TransmitterRingUnmask(Ring);
+ break;
+ }
- __TransmitterRingReleaseLock(Ring);
- __TransmitterRingUnmask(Ring);
+ if (__TransmitterRingDpcTimeout(Ring)) {
+ LARGE_INTEGER Delay;
+
+ Delay.QuadPart = TIME_RELATIVE(TIME_US(100));
+
+ KeSetTimer(&Ring->Timer, Delay, &Ring->TimerDpc);
+ break;
+ }
+ }
}
KSERVICE_ROUTINE TransmitterRingEvtchnCallback;
Ring->Events++;
- (VOID) KeInsertQueueDpc(&Ring->Dpc, NULL, NULL);
+ if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
+ Ring->Dpcs++;
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))
-
#define XENVIF_TRANSMITTER_WATCHDOG_PERIOD 30
static NTSTATUS
// Try to move things along
__TransmitterRingSend(Ring);
- TransmitterRingPoll(Ring);
+ (VOID) TransmitterRingPoll(Ring);
}
PacketsQueued = Ring->PacketsQueued;
InitializeListHead(&(*Ring)->PacketComplete);
KeInitializeDpc(&(*Ring)->Dpc, TransmitterRingDpc, *Ring);
+ KeInitializeTimer(&(*Ring)->Timer);
+ KeInitializeDpc(&(*Ring)->TimerDpc, TransmitterRingDpc, *Ring);
status = ThreadCreate(TransmitterRingWatchdog,
*Ring,
fail3:
Error("fail3\n");
+ RtlZeroMemory(&(*Ring)->TimerDpc, sizeof (KDPC));
+ RtlZeroMemory(&(*Ring)->Timer, sizeof (KTIMER));
RtlZeroMemory(&(*Ring)->Dpc, sizeof (KDPC));
RtlZeroMemory(&(*Ring)->PacketComplete, sizeof (LIST_ENTRY));
ASSERT(NT_SUCCESS(status));
KeSetTargetProcessorDpcEx(&Ring->Dpc, &ProcNumber);
+ KeSetTargetProcessorDpcEx(&Ring->TimerDpc, &ProcNumber);
(VOID) XENBUS_EVTCHN(Bind,
&Transmitter->EvtchnInterface,
__TransmitterRingAcquireLock(Ring);
ASSERT(Ring->Enabled);
- Ring->Enabled = FALSE;
// Release any fragments associated with a pending packet
Packet = __TransmitterRingUnprepareFragments(Ring);
// Try to move things along
__TransmitterRingSend(Ring);
- TransmitterRingPoll(Ring);
+ (VOID) TransmitterRingPoll(Ring);
if (State != XenbusStateConnected)
__TransmitterRingFakeResponses(Ring);
KeStallExecutionProcessor(1000); // 1ms
}
+ Ring->Enabled = FALSE;
+
__TransmitterRingReleaseLock(Ring);
}
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);
Ring = Transmitter->Ring[Index];
- (VOID) KeInsertQueueDpc(&Ring->Dpc, NULL, NULL);
+ if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
+ Ring->Dpcs++;
}
VOID