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

Re: [PATCH] Asynchronous power handling.


  • To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Paul Durrant <xadimgnik@xxxxxxxxx>
  • Date: Thu, 14 Mar 2024 10:30:41 +0000
  • Delivery-date: Thu, 14 Mar 2024 10:30:55 +0000
  • List-id: Developer list for the Windows PV Drivers subproject <win-pv-devel.lists.xenproject.org>

On 12/03/2024 07:23, Owen Smith wrote:
From: Martin Harvey <Martin.Harvey@xxxxxxxxxx>

Use completion routines and IO_WORKITEMs to handle power state transitions,
allowing execution to run at PASSIVE_LEVEL without blocking the current thread,
and avoid blocking all power IRPs while another is executing (power IRPs should
be synchronized by the power manager, but this doesnt appear to be the case in
all situations).

Signed-off-by: Martin Harvey <martin.harvey@xxxxxxxxxx>

Refactored

Unfortunately, not enough...

Signed-off-by: Owen Smith <owen.smith@xxxxxxxxx>

---
  src/xenvif/fdo.c | 803 +++++++++++++++++++++++++++++------------------
  src/xenvif/pdo.c | 263 +++++++---------
  2 files changed, 608 insertions(+), 458 deletions(-)

diff --git a/src/xenvif/fdo.c b/src/xenvif/fdo.c
index 451d582..7fa2d04 100644
--- a/src/xenvif/fdo.c
+++ b/src/xenvif/fdo.c
@@ -81,9 +81,9 @@ struct _XENVIF_FDO {
      ULONG                       Usage[DeviceUsageTypeDumpFile + 1];
      BOOLEAN                     NotDisableable;
- PXENVIF_THREAD SystemPowerThread;
+    PIO_WORKITEM                SystemPowerWorkItem;
      PIRP                        SystemPowerIrp;
-    PXENVIF_THREAD              DevicePowerThread;
+    PIO_WORKITEM                DevicePowerWorkItem;
      PIRP                        DevicePowerIrp;
CHAR VendorName[MAXNAMELEN];
@@ -2168,6 +2168,68 @@ FdoDispatchPnp(
      return status;
  }
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
+static VOID
+FdoDevicePowerUpWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
+    )
+{
+    PXENVIF_FDO         Fdo = (PXENVIF_FDO) Context;
+    PIRP                Irp;
+
+    UNREFERENCED_PARAMETER(DeviceObject);
+
+    Irp = InterlockedExchangePointer(&Fdo->DevicePowerIrp, NULL);
+    ASSERT(Irp != NULL);
+
+    (VOID) FdoD3ToD0(Fdo);
+
+    /* Cannot change Irp->IoStatus */
+    /* Continue completion chain */
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+FdoSetDevicePowerUpComplete(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PIRP            Irp,
+    IN  PVOID           Context
+    )
+{
+    PXENVIF_FDO         Fdo = (PXENVIF_FDO) Context;
+    PIO_STACK_LOCATION  StackLocation;
+    DEVICE_POWER_STATE  DeviceState;
+    PVOID               Exchange;
+
+    UNREFERENCED_PARAMETER(DeviceObject);
+
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+    /* Already marked pending by us */
+    Info("%s -> %s\n",

Lack of device name in the Info() message make it less useful

+         PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
+         PowerDeviceStateName(DeviceState));
+
+    /* Don't worry about IRP IoStatus */
+    ASSERT3U(DeviceState, ==, PowerDeviceD0);
+
+    Exchange = InterlockedExchangePointer(&Fdo->DevicePowerIrp, Irp);
+    ASSERT(Exchange == NULL);
+
+    IoQueueWorkItem(Fdo->DevicePowerWorkItem,
+                    FdoDevicePowerUpWorker,
+                    DelayedWorkQueue,
+                    Fdo);
+
+    /* Stop completion chain in all circumstances. */
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
  static FORCEINLINE NTSTATUS
  __FdoSetDevicePowerUp(
      IN  PXENVIF_FDO     Fdo,
@@ -2176,7 +2238,6 @@ __FdoSetDevicePowerUp(
  {
      PIO_STACK_LOCATION  StackLocation;
      DEVICE_POWER_STATE  DeviceState;
-    NTSTATUS            status;
Trace("====>\n"); @@ -2185,25 +2246,41 @@ __FdoSetDevicePowerUp( ASSERT3U(DeviceState, <, __FdoGetDevicePowerState(Fdo)); - status = FdoForwardIrpSynchronously(Fdo, Irp);
-    if (!NT_SUCCESS(status))
-        goto done;
+    IoMarkIrpPending(Irp);
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+    IoSetCompletionRoutine(Irp,
+                           FdoSetDevicePowerUpComplete,
+                           Fdo,
+                           TRUE,
+                           TRUE,
+                           TRUE);
- Info("%s: %s -> %s\n",
-         __FdoGetName(Fdo),
-         PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
-         PowerDeviceStateName(DeviceState));
+    (VOID) IoCallDriver(Fdo->LowerDeviceObject, Irp);
- ASSERT3U(DeviceState, ==, PowerDeviceD0);
-    status = FdoD3ToD0(Fdo);
-    ASSERT(NT_SUCCESS(status));
+    return STATUS_PENDING;
+}
-done:
-    Irp->IoStatus.Status = status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
+static VOID
+FdoDevicePowerDownWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
+    )
+{
+    PXENVIF_FDO         Fdo = (PXENVIF_FDO) Context;
+    PIRP                Irp;
- Trace("<==== (%08x)\n", status);
-    return status;
+    UNREFERENCED_PARAMETER(DeviceObject);
+
+    Irp = InterlockedExchangePointer(&Fdo->DevicePowerIrp, NULL);
+    ASSERT(Irp != NULL);
+
+    FdoD0ToD3(Fdo);
+
+    /* We are on dispatch path here. */
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+    IoCallDriver(Fdo->LowerDeviceObject, Irp);
  }
static FORCEINLINE NTSTATUS
@@ -2221,18 +2298,32 @@ __FdoSetDevicePowerDown(
ASSERT3U(DeviceState, >, __FdoGetDevicePowerState(Fdo)); - Info("%s: %s -> %s\n",
-         __FdoGetName(Fdo),
+    Info("%s -> %s\n",

Device name being gratuitously removed here.

           PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
           PowerDeviceStateName(DeviceState));
ASSERT3U(DeviceState, ==, PowerDeviceD3); - if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0)
-        FdoD0ToD3(Fdo);
+    /* All handled in dispatch, no extra error handling */
+    if (__FdoGetDevicePowerState(Fdo) != PowerDeviceD0) {
+        /* Not marked pending, can skip */

Inconsistent comment format.

+        IoSkipCurrentIrpStackLocation(Irp);
+        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+    } else {
+        PVOID           Exchange;
- IoSkipCurrentIrpStackLocation(Irp);
-    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+        IoMarkIrpPending(Irp);
+
+        Exchange = InterlockedExchangePointer(&Fdo->DevicePowerIrp, Irp);
+        ASSERT(Exchange == NULL);
+
+        IoQueueWorkItem(Fdo->DevicePowerWorkItem,
+                        FdoDevicePowerDownWorker,
+                        DelayedWorkQueue,
+                        Fdo);
+
+        status = STATUS_PENDING;
+    }
return status;
  }
@@ -2253,11 +2344,9 @@ __FdoSetDevicePower(
      PowerAction = StackLocation->Parameters.Power.ShutdownType;
Trace("====> (%s:%s)\n",
-          PowerDeviceStateName(DeviceState),
+          PowerDeviceStateName(DeviceState),
            PowerActionName(PowerAction));
- ASSERT3U(PowerAction, <, PowerActionShutdown);
-
      if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
          IoSkipCurrentIrpStackLocation(Irp);
          status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
@@ -2271,7 +2360,7 @@ __FdoSetDevicePower(
done:
      Trace("<==== (%s:%s)(%08x)\n",
-          PowerDeviceStateName(DeviceState),
+          PowerDeviceStateName(DeviceState),
            PowerActionName(PowerAction),
            status);
      return status;
@@ -2279,8 +2368,8 @@ done:
__drv_functionClass(REQUEST_POWER_COMPLETE)
  __drv_sameIRQL
-VOID
-__FdoRequestSetDevicePower(
+static VOID
+FdoRequestSetDevicePowerUpComplete(
      IN  PDEVICE_OBJECT      DeviceObject,
      IN  UCHAR               MinorFunction,
      IN  POWER_STATE         PowerState,
@@ -2288,47 +2377,130 @@ __FdoRequestSetDevicePower(
      IN  PIO_STATUS_BLOCK    IoStatus
      )
  {
-    PKEVENT                 Event = Context;
+    PIRP                    Irp = (PIRP) Context;
UNREFERENCED_PARAMETER(DeviceObject);
      UNREFERENCED_PARAMETER(MinorFunction);
      UNREFERENCED_PARAMETER(PowerState);
+    UNREFERENCED_PARAMETER(IoStatus);
- ASSERT(NT_SUCCESS(IoStatus->Status));
-
-    KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+    /* Although can change Irp->IoStatus for pended IRP, drivers should not 
fail this. */

Again, wrong comment style.

+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
  }
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
  static VOID
-FdoRequestSetDevicePower(
-    IN  PXENVIF_FDO         Fdo,
-    IN  DEVICE_POWER_STATE  DeviceState
+FdoSystemPowerUpWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
      )
  {
-    POWER_STATE             PowerState;
-    KEVENT                  Event;
-    NTSTATUS                status;
+    PXENVIF_FDO         Fdo = (PXENVIF_FDO) Context;
+    PIRP                Irp;
+    PIO_STACK_LOCATION  StackLocation;
+    SYSTEM_POWER_STATE  SystemState;
+    POWER_STATE         PowerState;
+    NTSTATUS            status;
- Trace("%s\n", PowerDeviceStateName(DeviceState));
+    UNREFERENCED_PARAMETER(DeviceObject);
- ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+    Irp = InterlockedExchangePointer(&Fdo->SystemPowerIrp, NULL);
+    ASSERT(Irp != NULL);
- PowerState.DeviceState = DeviceState;
-    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);;
+    SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+    Info("%s -> %s\n",

Lack of device name in Info() again.

+         PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
+         PowerSystemStateName(SystemState));
+
+    __FdoSetSystemPowerState(Fdo, PowerSystemHibernate);
+    FdoS4ToS3(Fdo);
+    __FdoSetSystemPowerState(Fdo, SystemState);
+
+    PowerState.DeviceState = 
Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
status = PoRequestPowerIrp(Fdo->LowerDeviceObject,
                                 IRP_MN_SET_POWER,
                                 PowerState,
-                               __FdoRequestSetDevicePower,
-                               &Event,
+                               FdoRequestSetDevicePowerUpComplete,
+                               Irp,
                                 NULL);
-    ASSERT(NT_SUCCESS(status));
- (VOID) KeWaitForSingleObject(&Event,
-                                 Executive,
-                                 KernelMode,
-                                 FALSE,
-                                 NULL);
+    /* Whatever happens, we have stopped completion processing for SIrp,
+      to restart SIrp processing, call IoCompleteRequest. */

And again. In fact they are everywhere; please remove them or fix them. TBH it looks like many of them are OTT and can be removed.

+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    return; /* FdoRequestSetDevicePowerUpComplete will complete the request.*/
+
+fail1:
+    Error("fail1 - but continue IRP processing. (%08x)\n", status);
+    /* Although can change Irp->IoStatus for pended IRP, drivers should not 
fail this. */
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+FdoSetSystemPowerUpComplete(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PIRP            Irp,
+    IN  PVOID           Context
+    )
+{
+    PXENVIF_FDO         Fdo = (PXENVIF_FDO) Context;
+    PIO_STACK_LOCATION  StackLocation;
+    SYSTEM_POWER_STATE  SystemState;
+    POWER_STATE         PowerState;
+    NTSTATUS            status;
+
+    UNREFERENCED_PARAMETER(DeviceObject);
+
+    /* IRP marked as pending on dispatch path, no need to check pending 
returned */
+
+    /* Don't worry about IRP IoStatus */
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+    if (SystemState < PowerSystemHibernate &&
+        __FdoGetSystemPowerState(Fdo) >= PowerSystemHibernate) {
+        PVOID           Exchange;
+
+        Exchange = InterlockedExchangePointer(&Fdo->SystemPowerIrp, Irp);
+        ASSERT(Exchange == NULL);
+
+        IoQueueWorkItem(Fdo->SystemPowerWorkItem,
+                        FdoSystemPowerUpWorker,
+                        DelayedWorkQueue,
+                        Fdo);
+    } else {
+        Info("%s -> %s\n",

Lack of device name in Info() again.

+             PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
+             PowerSystemStateName(SystemState));
+
+        __FdoSetSystemPowerState(Fdo, SystemState);
+
+        PowerState.DeviceState = 
Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
+
+        status = PoRequestPowerIrp(Fdo->LowerDeviceObject,
+                                   IRP_MN_SET_POWER,
+                                   PowerState,
+                                   FdoRequestSetDevicePowerUpComplete,
+                                   Irp,
+                                   NULL);
+        if (!NT_SUCCESS(status))
+            goto fail1;
+    }
+
+    /* Will later complete the IRP (which is marked pending, in worker or 2nd 
level comp routine.)*/
+    return STATUS_MORE_PROCESSING_REQUIRED;
+
+fail1:
+    Error("fail1 - but continue IRP processing. (%08x)\n", status);
+    /* marked pending on dispatch path, don't change Irp->IoStatus, keep 
going.*/
+    return STATUS_CONTINUE_COMPLETION;
  }
static FORCEINLINE NTSTATUS
@@ -2337,42 +2509,103 @@ __FdoSetSystemPowerUp(
      IN  PIRP            Irp
      )
  {
-
      PIO_STACK_LOCATION  StackLocation;
      SYSTEM_POWER_STATE  SystemState;
-    DEVICE_POWER_STATE  DeviceState;
-    NTSTATUS            status;
StackLocation = IoGetCurrentIrpStackLocation(Irp);
      SystemState = StackLocation->Parameters.Power.State.SystemState;
ASSERT3U(SystemState, <, __FdoGetSystemPowerState(Fdo)); - status = FdoForwardIrpSynchronously(Fdo, Irp);
-    if (!NT_SUCCESS(status))
-        goto done;
+    /* IRP already pended, and we want to complete it *after* completion 
routine. */
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+    IoSetCompletionRoutine(Irp,
+                           FdoSetSystemPowerUpComplete,
+                           Fdo,
+                           TRUE,
+                           TRUE,
+                           TRUE);
- Info("%s: %s -> %s\n",
-         __FdoGetName(Fdo),
-         PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
-         PowerSystemStateName(SystemState));
+    IoCallDriver(Fdo->LowerDeviceObject, Irp);
- if (SystemState < PowerSystemHibernate &&
-        __FdoGetSystemPowerState(Fdo) >= PowerSystemHibernate) {
-        __FdoSetSystemPowerState(Fdo, PowerSystemHibernate);
-        FdoS4ToS3(Fdo);
-    }
+    return STATUS_PENDING;
+}
+
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
+static VOID
+FdoSystemPowerDownWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
+    )
+{
+    PXENVIF_FDO         Fdo = (PXENVIF_FDO) Context;
+    PIRP                Irp;
+    PIO_STACK_LOCATION  StackLocation;
+    SYSTEM_POWER_STATE  SystemState;
+
+    UNREFERENCED_PARAMETER(DeviceObject);
+
+    Irp = InterlockedExchangePointer(&Fdo->SystemPowerIrp, NULL);
+    ASSERT(Irp != NULL);
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+    __FdoSetSystemPowerState(Fdo, PowerSystemSleeping3);
+    FdoS3ToS4(Fdo);
      __FdoSetSystemPowerState(Fdo, SystemState);
- DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
-    FdoRequestSetDevicePower(Fdo, DeviceState);
+    IoCopyCurrentIrpStackLocationToNext(Irp); /* Irp has been pended */
+    IoCallDriver(Fdo->LowerDeviceObject, Irp);
+}
-done:
-    Irp->IoStatus.Status = status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+__drv_functionClass(REQUEST_POWER_COMPLETE)
+__drv_sameIRQL
+static VOID
+FdoRequestSetDevicePowerDownComplete(
+    IN  PDEVICE_OBJECT      DeviceObject,
+    IN  UCHAR               MinorFunction,
+    IN  POWER_STATE         PowerState,
+    IN  PVOID               Context,
+    IN  PIO_STATUS_BLOCK    IoStatus
+    )
+{
+    PIRP                    Irp = (PIRP) Context;
+    PIO_STACK_LOCATION      StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    PDEVICE_OBJECT          UpperDeviceObject = StackLocation->DeviceObject;
+    PXENVIF_DX              Dx = 
(PXENVIF_DX)UpperDeviceObject->DeviceExtension;
+    PXENVIF_FDO             Fdo = Dx->Fdo;
+    SYSTEM_POWER_STATE      SystemState = 
StackLocation->Parameters.Power.State.SystemState;
- return status;
+    UNREFERENCED_PARAMETER(DeviceObject);
+    UNREFERENCED_PARAMETER(MinorFunction);
+    UNREFERENCED_PARAMETER(PowerState);
+
+    if (!NT_SUCCESS(IoStatus->Status))
+        Error("fail1 - but continue IRP processing. (%08x)\n", 
IoStatus->Status);
+
+    Info("%s -> %s\n",
+        PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
+        PowerSystemStateName(SystemState));
+
+    if (SystemState >= PowerSystemHibernate &&
+        __FdoGetSystemPowerState(Fdo) < PowerSystemHibernate) {
+        PVOID Exchange;
+
+        Exchange = InterlockedExchangePointer(&Fdo->SystemPowerIrp, Irp);
+        ASSERT(Exchange == NULL);
+
+        IoQueueWorkItem(Fdo->DevicePowerWorkItem,
+                        FdoSystemPowerDownWorker,
+                        DelayedWorkQueue,
+                        Fdo);
+    } else {
+        __FdoSetSystemPowerState(Fdo, SystemState);
+
+        IoCopyCurrentIrpStackLocationToNext(Irp); /* Irp has been pended */
+        IoCallDriver(Fdo->LowerDeviceObject, Irp);
+    }
  }
static FORCEINLINE NTSTATUS
@@ -2383,33 +2616,44 @@ __FdoSetSystemPowerDown(
  {
      PIO_STACK_LOCATION  StackLocation;
      SYSTEM_POWER_STATE  SystemState;
-    DEVICE_POWER_STATE  DeviceState;
+    POWER_STATE         PowerState;
      NTSTATUS            status;
StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    BUG_ON(StackLocation->DeviceObject != Fdo->Dx->DeviceObject);
      SystemState = StackLocation->Parameters.Power.State.SystemState;
ASSERT3U(SystemState, >, __FdoGetSystemPowerState(Fdo)); - DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
-
-    FdoRequestSetDevicePower(Fdo, DeviceState);
+    PowerState.DeviceState = 
Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
- Info("%s: %s -> %s\n",
-         __FdoGetName(Fdo),
-         PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
-         PowerSystemStateName(SystemState));
-
-    if (SystemState >= PowerSystemHibernate &&
-        __FdoGetSystemPowerState(Fdo) < PowerSystemHibernate) {
-        __FdoSetSystemPowerState(Fdo, PowerSystemSleeping3);
-        FdoS3ToS4(Fdo);
+    if (SystemState >= PowerSystemShutdown) {
+        /* No DIrp generation, no FDO Powerdown.
+           Legacy shutdown just yanks system power.
+           Best device state for S5 is advertised as D3,
+           which is not *really* the case, but we can't increase it. */
+        IoCopyCurrentIrpStackLocationToNext(Irp); /* Irp has been pended */
+        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+    } else {
+        status = PoRequestPowerIrp(Fdo->LowerDeviceObject,
+                                   IRP_MN_SET_POWER,
+                                   PowerState,
+                                   FdoRequestSetDevicePowerDownComplete,
+                                   Irp,
+                                   NULL);
+        if (!NT_SUCCESS(status))
+            goto fail1;
      }
+    /* IRP already marked pending - nothing more to do if awaiting callback. */
- __FdoSetSystemPowerState(Fdo, SystemState);
+    return status;
- IoSkipCurrentIrpStackLocation(Irp);
-    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+fail1:
+    /* In theory could change IRP status, but are not supposed to fail this 
IRP. */
+    Error("fail1 - but continue IRP processing. (%08x)\n", status);
+
+    IoCopyCurrentIrpStackLocationToNext(Irp); /* Irp has been pended */
+    IoCallDriver(Fdo->LowerDeviceObject, Irp);
return status;
  }
@@ -2429,29 +2673,31 @@ __FdoSetSystemPower(
      SystemState = StackLocation->Parameters.Power.State.SystemState;
      PowerAction = StackLocation->Parameters.Power.ShutdownType;
+ /* IRP_MN_SET_POWER Setting system power, IRP's *must* be pended. */
+    IoMarkIrpPending(Irp);
+
      Trace("====> (%s:%s)\n",
-          PowerSystemStateName(SystemState),
+          PowerSystemStateName(SystemState),
            PowerActionName(PowerAction));
- ASSERT3U(PowerAction, <, PowerActionShutdown);
-
      if (SystemState == __FdoGetSystemPowerState(Fdo)) {
-        IoSkipCurrentIrpStackLocation(Irp);
+        IoCopyCurrentIrpStackLocationToNext(Irp); /* Pended, copy not skip */
          status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
goto done;
      }
- status = (SystemState < __FdoGetSystemPowerState(Fdo)) ?
+    status = SystemState < __FdoGetSystemPowerState(Fdo) ?
               __FdoSetSystemPowerUp(Fdo, Irp) :
               __FdoSetSystemPowerDown(Fdo, Irp);
done:
      Trace("<==== (%s:%s)(%08x)\n",
-          PowerSystemStateName(SystemState),
+          PowerSystemStateName(SystemState),
            PowerActionName(PowerAction),
            status);
-    return status;
+
+    return STATUS_PENDING;
  }
static FORCEINLINE NTSTATUS
@@ -2469,10 +2715,9 @@ __FdoQueryDevicePowerUp(
ASSERT3U(DeviceState, <, __FdoGetDevicePowerState(Fdo)); - status = FdoForwardIrpSynchronously(Fdo, Irp);
-
-    Irp->IoStatus.Status = status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    /* N.B. Shutdown / hibernation failures caused by our device state could 
be vetoed here. */
+    IoSkipCurrentIrpStackLocation(Irp);
+    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
return status;
  }
@@ -2492,6 +2737,7 @@ __FdoQueryDevicePowerDown(
ASSERT3U(DeviceState, >, __FdoGetDevicePowerState(Fdo)); + /* N.B. Shutdown / hibernation failures caused by our device state could be vetoed here. */
      IoSkipCurrentIrpStackLocation(Irp);
      status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
@@ -2514,11 +2760,9 @@ __FdoQueryDevicePower(
      PowerAction = StackLocation->Parameters.Power.ShutdownType;
Trace("====> (%s:%s)\n",
-          PowerDeviceStateName(DeviceState),
+          PowerDeviceStateName(DeviceState),
            PowerActionName(PowerAction));
- ASSERT3U(PowerAction, <, PowerActionShutdown);
-
      if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
          IoSkipCurrentIrpStackLocation(Irp);
          status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
@@ -2532,7 +2776,7 @@ __FdoQueryDevicePower(
done:
      Trace("<==== (%s:%s)(%08x)\n",
-          PowerDeviceStateName(DeviceState),
+          PowerDeviceStateName(DeviceState),
            PowerActionName(PowerAction),
            status);
      return status;
@@ -2540,8 +2784,8 @@ done:
__drv_functionClass(REQUEST_POWER_COMPLETE)
  __drv_sameIRQL
-VOID
-__FdoRequestQueryDevicePower(
+static VOID
+FdoRequestQueryDevicePowerUpComplete(
      IN  PDEVICE_OBJECT      DeviceObject,
      IN  UCHAR               MinorFunction,
      IN  POWER_STATE         PowerState,
@@ -2549,47 +2793,58 @@ __FdoRequestQueryDevicePower(
      IN  PIO_STATUS_BLOCK    IoStatus
      )
  {
-    PKEVENT                 Event = Context;
+    PIRP                    Irp = (PIRP) Context;
UNREFERENCED_PARAMETER(DeviceObject);
      UNREFERENCED_PARAMETER(MinorFunction);
      UNREFERENCED_PARAMETER(PowerState);
- ASSERT(NT_SUCCESS(IoStatus->Status));
+    if (!NT_SUCCESS(IoStatus->Status))
+        Irp->IoStatus.Status = IoStatus->Status;
- KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
  }
-static VOID
-FdoRequestQueryDevicePower(
-    IN  PXENVIF_FDO         Fdo,
-    IN  DEVICE_POWER_STATE  DeviceState
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+FdoQuerySystemPowerUpComplete(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PIRP            Irp,
+    IN  PVOID           Context
      )
  {
-    POWER_STATE             PowerState;
-    KEVENT                  Event;
-    NTSTATUS                status;
-
-    Trace("%s\n", PowerDeviceStateName(DeviceState));
+    PXENVIF_FDO         Fdo = (PXENVIF_FDO) Context;
+    PIO_STACK_LOCATION  StackLocation;
+    SYSTEM_POWER_STATE  SystemState;
+    POWER_STATE         PowerState;
+    NTSTATUS            status;
- ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+    UNREFERENCED_PARAMETER(DeviceObject);
- PowerState.DeviceState = DeviceState;
-    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    /* IRP marked as pending on dispatch path. */
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    SystemState = StackLocation->Parameters.Power.State.SystemState;
+    PowerState.DeviceState = 
Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
status = PoRequestPowerIrp(Fdo->LowerDeviceObject,
                                 IRP_MN_QUERY_POWER,
                                 PowerState,
-                               __FdoRequestQueryDevicePower,
-                               &Event,
+                               FdoRequestQueryDevicePowerUpComplete,
+                               Irp,
                                 NULL);
-    ASSERT(NT_SUCCESS(status));
+    if (!NT_SUCCESS(status))
+        goto fail1;
- (VOID) KeWaitForSingleObject(&Event,
-                                 Executive,
-                                 KernelMode,
-                                 FALSE,
-                                 NULL);
+    /* Will later complete the IRP (which is marked pending, in 2nd level comp 
routine.)*/
+    return STATUS_MORE_PROCESSING_REQUIRED;
+
+fail1:
+    /* Irp marked as pending on dispatch path, so can change final IoStatus, 
pass to completion routine above. */
+    Error("fail1 (%08x)\n", status);
+    Irp->IoStatus.Status = status;
+
+    return STATUS_CONTINUE_COMPLETION;
  }
static FORCEINLINE NTSTATUS
@@ -2598,30 +2853,61 @@ __FdoQuerySystemPowerUp(
      IN  PIRP            Irp
      )
  {
-
      PIO_STACK_LOCATION  StackLocation;
      SYSTEM_POWER_STATE  SystemState;
-    DEVICE_POWER_STATE  DeviceState;
-    NTSTATUS            status;
StackLocation = IoGetCurrentIrpStackLocation(Irp);
      SystemState = StackLocation->Parameters.Power.State.SystemState;
ASSERT3U(SystemState, <, __FdoGetSystemPowerState(Fdo)); - status = FdoForwardIrpSynchronously(Fdo, Irp);
-    if (!NT_SUCCESS(status))
-        goto done;
+    IoMarkIrpPending(Irp); /* Must mark IRP pending because we want to 
complete it *after* completion routine. */
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+    IoSetCompletionRoutine(Irp,
+                           FdoQuerySystemPowerUpComplete,
+                           Fdo,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+    (VOID) IoCallDriver(Fdo->LowerDeviceObject, Irp);
- DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
+    return STATUS_PENDING;
+}
- FdoRequestQueryDevicePower(Fdo, DeviceState);
+__drv_functionClass(REQUEST_POWER_COMPLETE)
+__drv_sameIRQL
+static VOID
+FdoRequestQueryDevicePowerDownComplete(
+    IN  PDEVICE_OBJECT      DeviceObject,
+    IN  UCHAR               MinorFunction,
+    IN  POWER_STATE         PowerState,
+    IN  PVOID               Context,
+    IN  PIO_STATUS_BLOCK    IoStatus
+    )
+{
+    PIRP                    Irp = (PIRP) Context;
+    PIO_STACK_LOCATION      StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    PDEVICE_OBJECT          UpperDeviceObject = StackLocation->DeviceObject;
+    PXENVIF_DX              Dx = 
(PXENVIF_DX)UpperDeviceObject->DeviceExtension;
+    PXENVIF_FDO             Fdo = Dx->Fdo;
-done:
-    Irp->IoStatus.Status = status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    UNREFERENCED_PARAMETER(DeviceObject);
+    UNREFERENCED_PARAMETER(MinorFunction);
+    UNREFERENCED_PARAMETER(PowerState);
- return status;
+    if (!NT_SUCCESS(IoStatus->Status))
+        goto fail1;
+
+    IoCopyCurrentIrpStackLocationToNext(Irp); /* Irp has been pended. */
+    IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+    return;
+
+fail1:
+    Error("fail1 (%08x)\n", IoStatus->Status);
+
+    Irp->IoStatus.Status = IoStatus->Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
  }
static FORCEINLINE NTSTATUS
@@ -2632,7 +2918,7 @@ __FdoQuerySystemPowerDown(
  {
      PIO_STACK_LOCATION  StackLocation;
      SYSTEM_POWER_STATE  SystemState;
-    DEVICE_POWER_STATE  DeviceState;
+    POWER_STATE         PowerState;
      NTSTATUS            status;
StackLocation = IoGetCurrentIrpStackLocation(Irp);
@@ -2640,12 +2926,26 @@ __FdoQuerySystemPowerDown(
ASSERT3U(SystemState, >, __FdoGetSystemPowerState(Fdo)); - DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
+    PowerState.DeviceState = 
Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
- FdoRequestQueryDevicePower(Fdo, DeviceState);
+    status = PoRequestPowerIrp(Fdo->LowerDeviceObject,
+                               IRP_MN_QUERY_POWER,
+                               PowerState,
+                               FdoRequestQueryDevicePowerDownComplete,
+                               Irp,
+                               NULL);
+    if (!NT_SUCCESS(status))
+        goto fail1;
- IoSkipCurrentIrpStackLocation(Irp);
-    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+    IoMarkIrpPending(Irp);
+
+    return STATUS_PENDING;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    Irp->IoStatus.Status = status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
  }
@@ -2666,11 +2966,9 @@ __FdoQuerySystemPower(
      PowerAction = StackLocation->Parameters.Power.ShutdownType;
Trace("====> (%s:%s)\n",
-          PowerSystemStateName(SystemState),
+          PowerSystemStateName(SystemState),
            PowerActionName(PowerAction));
- ASSERT3U(PowerAction, <, PowerActionShutdown);
-
      if (SystemState == __FdoGetSystemPowerState(Fdo)) {
          IoSkipCurrentIrpStackLocation(Irp);
          status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
@@ -2684,183 +2982,91 @@ __FdoQuerySystemPower(
done:
      Trace("<==== (%s:%s)(%08x)\n",
-          PowerSystemStateName(SystemState),
+          PowerSystemStateName(SystemState),
            PowerActionName(PowerAction),
            status);
return status;
  }
-static NTSTATUS
-FdoDevicePower(
-    IN  PXENVIF_THREAD  Self,
-    IN  PVOID           Context
+static FORCEINLINE NTSTATUS
+__FdoDevicePower(
+    IN  PXENVIF_FDO     Fdo,
+    IN  PIRP            Irp
      )
  {
-    PXENVIF_FDO         Fdo = Context;
-    PKEVENT             Event;
-
-    Event = ThreadGetEvent(Self);
-
-    for (;;) {
-        PIRP                Irp;
-        PIO_STACK_LOCATION  StackLocation;
-        UCHAR               MinorFunction;
-
-        if (Fdo->DevicePowerIrp == NULL) {
-            (VOID) KeWaitForSingleObject(Event,
-                                         Executive,
-                                         KernelMode,
-                                         FALSE,
-                                         NULL);
-            KeClearEvent(Event);
-        }
-
-        if (ThreadIsAlerted(Self))
-            break;
-
-        Irp = Fdo->DevicePowerIrp;
-
-        if (Irp == NULL)
-            continue;
-
-        Fdo->DevicePowerIrp = NULL;
-        KeMemoryBarrier();
+    PIO_STACK_LOCATION  StackLocation;
+    NTSTATUS            status;
- StackLocation = IoGetCurrentIrpStackLocation(Irp);
-        MinorFunction = StackLocation->MinorFunction;
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
- switch (StackLocation->MinorFunction) {
-        case IRP_MN_SET_POWER:
-            (VOID) __FdoSetDevicePower(Fdo, Irp);
-            break;
+    switch (StackLocation->MinorFunction) {
+    case IRP_MN_SET_POWER:
+        status = __FdoSetDevicePower(Fdo, Irp);
+        break;
- case IRP_MN_QUERY_POWER:
-            (VOID) __FdoQueryDevicePower(Fdo, Irp);
-            break;
+    case IRP_MN_QUERY_POWER:
+        status = __FdoQueryDevicePower(Fdo, Irp);
+        break;
- default:
-            ASSERT(FALSE);
-            break;
-        }
+    default:
+        IoSkipCurrentIrpStackLocation(Irp);
+        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+        break;
      }
- return STATUS_SUCCESS;
+    return status;
  }
-static NTSTATUS
-FdoSystemPower(
-    IN  PXENVIF_THREAD  Self,
-    IN  PVOID           Context
+static FORCEINLINE NTSTATUS
+__FdoSystemPower(
+    IN  PXENVIF_FDO     Fdo,
+    IN  PIRP            Irp
      )
  {
-    PXENVIF_FDO         Fdo = Context;
-    PKEVENT             Event;
-
-    Event = ThreadGetEvent(Self);
-
-    for (;;) {
-        PIRP                Irp;
-        PIO_STACK_LOCATION  StackLocation;
-        UCHAR               MinorFunction;
-
-        if (Fdo->SystemPowerIrp == NULL) {
-            (VOID) KeWaitForSingleObject(Event,
-                                         Executive,
-                                         KernelMode,
-                                         FALSE,
-                                         NULL);
-            KeClearEvent(Event);
-        }
-
-        if (ThreadIsAlerted(Self))
-            break;
-
-        Irp = Fdo->SystemPowerIrp;
-
-        if (Irp == NULL)
-            continue;
-
-        Fdo->SystemPowerIrp = NULL;
-        KeMemoryBarrier();
+    PIO_STACK_LOCATION  StackLocation;
+    NTSTATUS            status;
- StackLocation = IoGetCurrentIrpStackLocation(Irp);
-        MinorFunction = StackLocation->MinorFunction;
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
- switch (StackLocation->MinorFunction) {
-        case IRP_MN_SET_POWER:
-            (VOID) __FdoSetSystemPower(Fdo, Irp);
-            break;
+    switch (StackLocation->MinorFunction) {
+    case IRP_MN_SET_POWER:
+        status = __FdoSetSystemPower(Fdo, Irp);
+        break;
- case IRP_MN_QUERY_POWER:
-            (VOID) __FdoQuerySystemPower(Fdo, Irp);
-            break;
+    case IRP_MN_QUERY_POWER:
+        status = __FdoQuerySystemPower(Fdo, Irp);
+        break;
- default:
-            ASSERT(FALSE);
-            break;
-        }
+    default:
+        IoSkipCurrentIrpStackLocation(Irp);
+        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+        break;
      }
- return STATUS_SUCCESS;
+    return status;
  }
static DECLSPEC_NOINLINE NTSTATUS
  FdoDispatchPower(
-    IN  PXENVIF_FDO     Fdo,
+    IN  PXENVIF_FDO   Fdo,
      IN  PIRP            Irp
      )
  {
      PIO_STACK_LOCATION  StackLocation;
-    UCHAR               MinorFunction;
      POWER_STATE_TYPE    PowerType;
-    POWER_ACTION        PowerAction;
      NTSTATUS            status;
StackLocation = IoGetCurrentIrpStackLocation(Irp);
-    MinorFunction = StackLocation->MinorFunction;
-
-    if (MinorFunction != IRP_MN_QUERY_POWER &&
-        MinorFunction != IRP_MN_SET_POWER) {
-        IoSkipCurrentIrpStackLocation(Irp);
-        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
-
-        goto done;
-    }
-
      PowerType = StackLocation->Parameters.Power.Type;
-    PowerAction = StackLocation->Parameters.Power.ShutdownType;
-
-    if (PowerAction >= PowerActionShutdown) {
-        IoSkipCurrentIrpStackLocation(Irp);
-        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
-
-        goto done;
-    }
switch (PowerType) {
      case DevicePowerState:
-        IoMarkIrpPending(Irp);
-
-        ASSERT3P(Fdo->DevicePowerIrp, ==, NULL);
-        Fdo->DevicePowerIrp = Irp;
-        KeMemoryBarrier();
-
-        ThreadWake(Fdo->DevicePowerThread);
-
-        status = STATUS_PENDING;
+        status = __FdoDevicePower(Fdo, Irp);
          break;
case SystemPowerState:
-        IoMarkIrpPending(Irp);
-
-        ASSERT3P(Fdo->SystemPowerIrp, ==, NULL);
-        Fdo->SystemPowerIrp = Irp;
-        KeMemoryBarrier();
-
-        ThreadWake(Fdo->SystemPowerThread);
-
-        status = STATUS_PENDING;
+        status = __FdoSystemPower(Fdo, Irp);
          break;
default:
@@ -2869,7 +3075,6 @@ FdoDispatchPower(
          break;
      }
-done:
      return status;
  }
@@ -3063,12 +3268,12 @@ FdoCreate(
      Fdo->LowerDeviceObject = IoAttachDeviceToDeviceStack(FunctionDeviceObject,
                                                           
PhysicalDeviceObject);
- status = ThreadCreate(FdoSystemPower, Fdo, &Fdo->SystemPowerThread);
-    if (!NT_SUCCESS(status))
+    Fdo->SystemPowerWorkItem = IoAllocateWorkItem(PhysicalDeviceObject);
+    if (Fdo->SystemPowerWorkItem == NULL)
          goto fail3;
- status = ThreadCreate(FdoDevicePower, Fdo, &Fdo->DevicePowerThread);
-    if (!NT_SUCCESS(status))
+    Fdo->DevicePowerWorkItem = IoAllocateWorkItem(PhysicalDeviceObject);
+    if (Fdo->DevicePowerWorkItem == NULL)
          goto fail4;
status = __FdoAcquireLowerBusInterface(Fdo);
@@ -3226,16 +3431,14 @@ fail6:
  fail5:
      Error("fail5\n");
- ThreadAlert(Fdo->DevicePowerThread);
-    ThreadJoin(Fdo->DevicePowerThread);
-    Fdo->DevicePowerThread = NULL;
-
+    IoFreeWorkItem(Fdo->DevicePowerWorkItem);
+    Fdo->DevicePowerWorkItem = NULL;
+
  fail4:
      Error("fail4\n");
- ThreadAlert(Fdo->SystemPowerThread);
-    ThreadJoin(Fdo->SystemPowerThread);
-    Fdo->SystemPowerThread = NULL;
+    IoFreeWorkItem(Fdo->SystemPowerWorkItem);
+    Fdo->SystemPowerWorkItem = NULL;
fail3:
      Error("fail3\n");
@@ -3311,13 +3514,11 @@ FdoDestroy(
__FdoReleaseLowerBusInterface(Fdo); - ThreadAlert(Fdo->DevicePowerThread);
-    ThreadJoin(Fdo->DevicePowerThread);
-    Fdo->DevicePowerThread = NULL;
+    IoFreeWorkItem(Fdo->DevicePowerWorkItem);
+    Fdo->DevicePowerWorkItem = NULL;
- ThreadAlert(Fdo->SystemPowerThread);
-    ThreadJoin(Fdo->SystemPowerThread);
-    Fdo->SystemPowerThread = NULL;
+    IoFreeWorkItem(Fdo->SystemPowerWorkItem);
+    Fdo->SystemPowerWorkItem = NULL;
IoDetachDevice(Fdo->LowerDeviceObject); diff --git a/src/xenvif/pdo.c b/src/xenvif/pdo.c
index 0cef2d5..2979f53 100644
--- a/src/xenvif/pdo.c
+++ b/src/xenvif/pdo.c
@@ -68,9 +68,9 @@
  struct _XENVIF_PDO {
      PXENVIF_DX                  Dx;
- PXENVIF_THREAD SystemPowerThread;
+    PIO_WORKITEM                SystemPowerWorkItem;
      PIRP                        SystemPowerIrp;
-    PXENVIF_THREAD              DevicePowerThread;
+    PIO_WORKITEM                DevicePowerWorkItem;
      PIRP                        DevicePowerIrp;
PXENVIF_FDO Fdo;
@@ -2365,28 +2365,31 @@ PdoDispatchPnp(
      return status;
  }
-static FORCEINLINE NTSTATUS
-__PdoSetDevicePower(
-    IN  PXENVIF_PDO     Pdo,
-    IN  PIRP            Irp
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
+static VOID
+PdoDevicePowerWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
      )
  {
+    PXENVIF_PDO         Pdo = (PXENVIF_PDO) Context;
+    PIRP                Irp;
      PIO_STACK_LOCATION  StackLocation;
      DEVICE_POWER_STATE  DeviceState;
      POWER_ACTION        PowerAction;
      NTSTATUS            status;
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+    Irp = InterlockedExchangePointer(&Pdo->DevicePowerIrp, NULL);
+    ASSERT(Irp != NULL);
+
      StackLocation = IoGetCurrentIrpStackLocation(Irp);
      DeviceState = StackLocation->Parameters.Power.State.DeviceState;
      PowerAction = StackLocation->Parameters.Power.ShutdownType;
- Trace("====> (%s) (%s:%s)\n",
-          __PdoGetName(Pdo),
-          PowerDeviceStateName(DeviceState),
-          PowerActionName(PowerAction));
-
-    ASSERT3U(PowerAction, <, PowerActionShutdown);
-
+    status = STATUS_SUCCESS;
      if (__PdoGetDevicePowerState(Pdo) > DeviceState) {
          Trace("%s: POWERING UP: %s -> %s\n",
                __PdoGetName(Pdo),
@@ -2395,7 +2398,6 @@ __PdoSetDevicePower(
ASSERT3U(DeviceState, ==, PowerDeviceD0);
          status = PdoD3ToD0(Pdo);
-        ASSERT(NT_SUCCESS(status));
      } else if (__PdoGetDevicePowerState(Pdo) < DeviceState) {
          Trace("%s: POWERING DOWN: %s -> %s\n",
                __PdoGetName(Pdo),
@@ -2406,77 +2408,71 @@ __PdoSetDevicePower(
          PdoD0ToD3(Pdo);
      }
+ /* Cannot fail the IRP at this point, keep going. */
      Irp->IoStatus.Status = STATUS_SUCCESS;
      IoCompleteRequest(Irp, IO_NO_INCREMENT);
- Trace("<==== (%s:%s)\n",
+    Trace("<==== (%s:%s)(%08x)\n",
            PowerDeviceStateName(DeviceState),
-          PowerActionName(PowerAction));
-
-    return STATUS_SUCCESS;
+          PowerActionName(PowerAction),
+          status);
  }
-static NTSTATUS
-PdoDevicePower(
-    IN  PXENVIF_THREAD  Self,
-    IN  PVOID           Context
+static FORCEINLINE NTSTATUS
+__PdoSetDevicePower(
+    IN  PXENVIF_PDO     Pdo,
+    IN  PIRP            Irp
      )
  {
-    PXENVIF_PDO         Pdo = Context;
-    PKEVENT             Event;
-
-    Event = ThreadGetEvent(Self);
-
-    for (;;) {
-        PIRP    Irp;
-
-        if (Pdo->DevicePowerIrp == NULL) {
-            (VOID) KeWaitForSingleObject(Event,
-                                         Executive,
-                                         KernelMode,
-                                         FALSE,
-                                         NULL);
-            KeClearEvent(Event);
-        }
+    PIO_STACK_LOCATION  StackLocation;
+    DEVICE_POWER_STATE  DeviceState;
+    POWER_ACTION        PowerAction;
+    PVOID               Exchange;
- if (ThreadIsAlerted(Self))
-            break;
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+    PowerAction = StackLocation->Parameters.Power.ShutdownType;
- Irp = Pdo->DevicePowerIrp;
+    Trace("====> (%s:%s)\n",
+          PowerDeviceStateName(DeviceState),
+          PowerActionName(PowerAction));
- if (Irp == NULL)
-            continue;
+    IoMarkIrpPending(Irp);
- Pdo->DevicePowerIrp = NULL;
-        KeMemoryBarrier();
+    Exchange = InterlockedExchangePointer(&Pdo->DevicePowerIrp, Irp);
+    ASSERT(Exchange == NULL);
- (VOID) __PdoSetDevicePower(Pdo, Irp);
-    }
+    IoQueueWorkItem(Pdo->DevicePowerWorkItem,
+                    PdoDevicePowerWorker,
+                    DelayedWorkQueue,
+                    Pdo);
- return STATUS_SUCCESS;
+    return STATUS_PENDING;
  }
-static FORCEINLINE NTSTATUS
-__PdoSetSystemPower(
-    IN  PXENVIF_PDO         Pdo,
-    IN  PIRP                Irp
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
+static VOID
+PdoSystemPowerWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
      )
  {
-    PIO_STACK_LOCATION      StackLocation;
-    SYSTEM_POWER_STATE      SystemState;
-    POWER_ACTION            PowerAction;
+    PXENVIF_PDO         Pdo = (PXENVIF_PDO) Context;
+    PIRP                Irp;
+    PIO_STACK_LOCATION  StackLocation;
+    SYSTEM_POWER_STATE  SystemState;
+    POWER_ACTION        PowerAction;
+
+    UNREFERENCED_PARAMETER(DeviceObject);
+
+    Irp = InterlockedExchangePointer(&Pdo->SystemPowerIrp, NULL);
+    ASSERT(Irp != NULL);
StackLocation = IoGetCurrentIrpStackLocation(Irp);
      SystemState = StackLocation->Parameters.Power.State.SystemState;
      PowerAction = StackLocation->Parameters.Power.ShutdownType;
- Trace("====> (%s) (%s:%s)\n",
-          __PdoGetName(Pdo),
-          PowerSystemStateName(SystemState),
-          PowerActionName(PowerAction));
-
-    ASSERT3U(PowerAction, <, PowerActionShutdown);
-
      if (__PdoGetSystemPowerState(Pdo) > SystemState) {
          if (SystemState < PowerSystemHibernate &&
              __PdoGetSystemPowerState(Pdo) >= PowerSystemHibernate) {
@@ -2488,6 +2484,7 @@ __PdoSetSystemPower(
                __PdoGetName(Pdo),
                PowerSystemStateName(__PdoGetSystemPowerState(Pdo)),
                PowerSystemStateName(SystemState));
+
      } else if (__PdoGetSystemPowerState(Pdo) < SystemState) {
          Trace("%s: POWERING DOWN: %s -> %s\n",
                __PdoGetName(Pdo),
@@ -2509,97 +2506,60 @@ __PdoSetSystemPower(
      Trace("<==== (%s:%s)\n",
            PowerSystemStateName(SystemState),
            PowerActionName(PowerAction));
-
-    return STATUS_SUCCESS;
  }
-static NTSTATUS
-PdoSystemPower(
-    IN  PXENVIF_THREAD  Self,
-    IN  PVOID           Context
+static FORCEINLINE NTSTATUS
+__PdoSetSystemPower(
+    IN  PXENVIF_PDO     Pdo,
+    IN  PIRP            Irp
      )
  {
-    PXENVIF_PDO         Pdo = Context;
-    PKEVENT             Event;
-
-    Event = ThreadGetEvent(Self);
-
-    for (;;) {
-        PIRP    Irp;
-
-        if (Pdo->SystemPowerIrp == NULL) {
-            (VOID) KeWaitForSingleObject(Event,
-                                         Executive,
-                                         KernelMode,
-                                         FALSE,
-                                         NULL);
-            KeClearEvent(Event);
-        }
+    PIO_STACK_LOCATION  StackLocation;
+    SYSTEM_POWER_STATE  SystemState;
+    POWER_ACTION        PowerAction;
+    PVOID               Exchange;
- if (ThreadIsAlerted(Self))
-            break;
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    SystemState = StackLocation->Parameters.Power.State.SystemState;
+    PowerAction = StackLocation->Parameters.Power.ShutdownType;
- Irp = Pdo->SystemPowerIrp;
+    Trace("====> (%s:%s)\n",
+          PowerSystemStateName(SystemState),
+          PowerActionName(PowerAction));
- if (Irp == NULL)
-            continue;
+    IoMarkIrpPending(Irp);
- Pdo->SystemPowerIrp = NULL;
-        KeMemoryBarrier();
+    Exchange = InterlockedExchangePointer(&Pdo->SystemPowerIrp, Irp);
+    ASSERT(Exchange == NULL);
- (VOID) __PdoSetSystemPower(Pdo, Irp);
-    }
+    IoQueueWorkItem(Pdo->SystemPowerWorkItem,
+                    PdoSystemPowerWorker,
+                    DelayedWorkQueue,
+                    Pdo);
- return STATUS_SUCCESS;
+    return STATUS_PENDING;
  }
-static DECLSPEC_NOINLINE NTSTATUS
-PdoSetPower(
+static FORCEINLINE NTSTATUS
+__PdoSetPower(
      IN  PXENVIF_PDO     Pdo,
      IN  PIRP            Irp
      )
  {
      PIO_STACK_LOCATION  StackLocation;
      POWER_STATE_TYPE    PowerType;
-    POWER_ACTION        PowerAction;
      NTSTATUS            status;
StackLocation = IoGetCurrentIrpStackLocation(Irp);
      PowerType = StackLocation->Parameters.Power.Type;
-    PowerAction = StackLocation->Parameters.Power.ShutdownType;
-
-    if (PowerAction >= PowerActionShutdown) {
-        Irp->IoStatus.Status = STATUS_SUCCESS;
-
-        status = Irp->IoStatus.Status;
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-        goto done;
-    }
switch (PowerType) {
      case DevicePowerState:
-        IoMarkIrpPending(Irp);
-
-        ASSERT3P(Pdo->DevicePowerIrp, ==, NULL);
-        Pdo->DevicePowerIrp = Irp;
-        KeMemoryBarrier();
-
-        ThreadWake(Pdo->DevicePowerThread);
-
-        status = STATUS_PENDING;
+        status = __PdoSetDevicePower(Pdo, Irp);
          break;
case SystemPowerState:
-        IoMarkIrpPending(Irp);
-
-        ASSERT3P(Pdo->SystemPowerIrp, ==, NULL);
-        Pdo->SystemPowerIrp = Irp;
-        KeMemoryBarrier();
-
-        ThreadWake(Pdo->SystemPowerThread);
-
-        status = STATUS_PENDING;
+        status = __PdoSetSystemPower(Pdo, Irp);
          break;
default:
@@ -2608,48 +2568,41 @@ PdoSetPower(
          break;
      }
-done:
      return status;
  }
-static DECLSPEC_NOINLINE NTSTATUS
-PdoQueryPower(
-    IN  PXENVIF_PDO     Pdo,
-    IN  PIRP            Irp
+static FORCEINLINE NTSTATUS
+__PdoQueryPower(
+    IN  PXENVIF_PDO Pdo,
+    IN  PIRP        Irp
      )
  {
-    NTSTATUS            status;
-
      UNREFERENCED_PARAMETER(Pdo);
Irp->IoStatus.Status = STATUS_SUCCESS;
-
-    status = Irp->IoStatus.Status;
      IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-    return status;
+
+    return STATUS_SUCCESS;
  }
-static DECLSPEC_NOINLINE NTSTATUS
+static NTSTATUS
  PdoDispatchPower(
      IN  PXENVIF_PDO     Pdo,
      IN  PIRP            Irp
      )
  {
      PIO_STACK_LOCATION  StackLocation;
-    UCHAR               MinorFunction;
      NTSTATUS            status;
StackLocation = IoGetCurrentIrpStackLocation(Irp);
-    MinorFunction = StackLocation->MinorFunction;
switch (StackLocation->MinorFunction) {
      case IRP_MN_SET_POWER:
-        status = PdoSetPower(Pdo, Irp);
+        status = __PdoSetPower(Pdo, Irp);
          break;
case IRP_MN_QUERY_POWER:
-        status = PdoQueryPower(Pdo, Irp);
+        status = __PdoQueryPower(Pdo, Irp);
          break;
default:
@@ -2762,12 +2715,12 @@ PdoCreate(
      Pdo->Dx = Dx;
      Pdo->Fdo = Fdo;
- status = ThreadCreate(PdoSystemPower, Pdo, &Pdo->SystemPowerThread);
-    if (!NT_SUCCESS(status))
+    Pdo->SystemPowerWorkItem = IoAllocateWorkItem(PhysicalDeviceObject);
+    if (Pdo->SystemPowerWorkItem == NULL)
          goto fail3;
- status = ThreadCreate(PdoDevicePower, Pdo, &Pdo->DevicePowerThread);
-    if (!NT_SUCCESS(status))
+    Pdo->DevicePowerWorkItem = IoAllocateWorkItem(PhysicalDeviceObject);
+    if (Pdo->DevicePowerWorkItem == NULL)
          goto fail4;
__PdoSetName(Pdo, Number);
@@ -2860,16 +2813,14 @@ fail6:
  fail5:
      Error("fail5\n");
- ThreadAlert(Pdo->DevicePowerThread);
-    ThreadJoin(Pdo->DevicePowerThread);
-    Pdo->DevicePowerThread = NULL;
+    IoFreeWorkItem(Pdo->DevicePowerWorkItem);
+    Pdo->DevicePowerWorkItem = NULL;
fail4:
      Error("fail4\n");
- ThreadAlert(Pdo->SystemPowerThread);
-    ThreadJoin(Pdo->SystemPowerThread);
-    Pdo->SystemPowerThread = NULL;
+    IoFreeWorkItem(Pdo->SystemPowerWorkItem);
+    Pdo->SystemPowerWorkItem = NULL;
fail3:
      Error("fail3\n");
@@ -2939,13 +2890,11 @@ PdoDestroy(
__PdoClearPermanentAddress(Pdo); - ThreadAlert(Pdo->DevicePowerThread);
-    ThreadJoin(Pdo->DevicePowerThread);
-    Pdo->DevicePowerThread = NULL;
+    IoFreeWorkItem(Pdo->DevicePowerWorkItem);
+    Pdo->DevicePowerWorkItem = NULL;
- ThreadAlert(Pdo->SystemPowerThread);
-    ThreadJoin(Pdo->SystemPowerThread);
-    Pdo->SystemPowerThread = NULL;
+    IoFreeWorkItem(Pdo->SystemPowerWorkItem);
+    Pdo->SystemPowerWorkItem = NULL;
Pdo->Fdo = NULL;
      Pdo->Dx = NULL;




 


Rackspace

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