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

[RFC PATCH 2/3] [XenBus] Asynchronous power handling.



From: Martin Harvey <Martin.Harvey@xxxxxxxxxx>

Replace a static, single thread for System and Device power transitions with
an IO_WORKITEM for each transition. IO_WORKITEMs are only used when a transition
requires calling codepaths that must be called at PASSIVE_LEVEL.
Move the bulk of power transitions to pending IRPs and IRP completion routines.

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

Refactored to only apply to XenBus power

Signed-off-by: Owen Smith <owen.smith@xxxxxxxxx>
---
 src/xenbus/fdo.c | 792 ++++++++++++++++++++++++++---------------------
 src/xenbus/pdo.c | 250 ++++++---------
 2 files changed, 534 insertions(+), 508 deletions(-)

diff --git a/src/xenbus/fdo.c b/src/xenbus/fdo.c
index 976a7a3..3d35e77 100644
--- a/src/xenbus/fdo.c
+++ b/src/xenbus/fdo.c
@@ -107,9 +107,9 @@ struct _XENBUS_FDO {
     ULONG                           Usage[DeviceUsageTypeDumpFile + 1];
     BOOLEAN                         NotDisableable;
 
-    PXENBUS_THREAD                  SystemPowerThread;
+    PIO_WORKITEM                    SystemPowerWorkItem;
     PIRP                            SystemPowerIrp;
-    PXENBUS_THREAD                  DevicePowerThread;
+    PIO_WORKITEM                    DevicePowerWorkItem;
     PIRP                            DevicePowerIrp;
 
     CHAR                            VendorName[MAXNAMELEN];
@@ -4800,38 +4800,105 @@ FdoDispatchPnp(
     return status;
 }
 
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
+static VOID
+FdoSetDevcePowerUpWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
+    )
+{
+    PXENBUS_FDO         Fdo = (PXENBUS_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
-FdoSetDevicePowerUp(
-    IN  PXENBUS_FDO     Fdo,
-    IN  PIRP            Irp
+FdoSetDevicePowerUpComplete(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PIRP            Irp,
+    IN  PVOID           Context
     )
 {
+    PXENBUS_FDO         Fdo = (PXENBUS_FDO) Context;
     PIO_STACK_LOCATION  StackLocation;
     DEVICE_POWER_STATE  DeviceState;
-    NTSTATUS            status;
+
+    UNREFERENCED_PARAMETER(DeviceObject);
 
     StackLocation = IoGetCurrentIrpStackLocation(Irp);
     DeviceState = StackLocation->Parameters.Power.State.DeviceState;
 
-    ASSERT3U(DeviceState, <,  __FdoGetDevicePowerState(Fdo));
-
-    status = FdoForwardIrpSynchronously(Fdo, Irp);
-    if (!NT_SUCCESS(status))
-        goto done;
-
-    Info("%s: %s -> %s\n",
-         __FdoGetName(Fdo),
+    /* Already marked pending by us */
+    Info("%s -> %s\n",
          DevicePowerStateName(__FdoGetDevicePowerState(Fdo)),
          DevicePowerStateName(DeviceState));
 
+    /* Don't worry about IRP IoStatus */
     ASSERT3U(DeviceState, ==, PowerDeviceD0);
-    status = FdoD3ToD0(Fdo);
-    ASSERT(NT_SUCCESS(status));
 
-done:
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    (VOID) InterlockedExchangePointer(&Fdo->DevicePowerIrp, Irp);
 
-    return status;
+    IoQueueWorkItem(Fdo->DevicePowerWorkItem,
+                    FdoSetDevcePowerUpWorker,
+                    DelayedWorkQueue,
+                    Fdo);
+
+    /* Stop completion chain in all circumstances. */
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static NTSTATUS
+FdoSetDevicePowerUp(
+    IN  PXENBUS_FDO     Fdo,
+    IN  PIRP            Irp
+    )
+{
+    IoMarkIrpPending(Irp);
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+    IoSetCompletionRoutine(Irp,
+                           FdoSetDevicePowerUpComplete,
+                           Fdo,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+    IoCallDriver(Fdo->LowerDeviceObject, Irp);
+    return STATUS_PENDING;
+}
+
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
+static VOID
+FdoSetDevicePowerDownWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
+    )
+{
+    PXENBUS_FDO         Fdo = (PXENBUS_FDO)Context;
+    PIRP                Irp;
+
+    UNREFERENCED_PARAMETER(DeviceObject);
+
+    Irp = InterlockedExchangePointer(&Fdo->DevicePowerIrp, NULL);
+    ASSERT(Irp != NULL);
+
+    FdoD0ToD3(Fdo);
+
+    /* We are on dispatch path here, irp pended. */
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+    IoCallDriver(Fdo->LowerDeviceObject, Irp);
 }
 
 static NTSTATUS
@@ -4856,12 +4923,24 @@ FdoSetDevicePowerDown(
 
     ASSERT3U(DeviceState, ==, PowerDeviceD3);
 
-    if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0)
-        FdoD0ToD3(Fdo);
+    if (__FdoGetDevicePowerState(Fdo) != PowerDeviceD0) {
+        IoSkipCurrentIrpStackLocation(Irp);
+        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
 
-    status = FdoForwardIrpSynchronously(Fdo, Irp);
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        goto done;
+    }
+
+    IoMarkIrpPending(Irp);
+    status = STATUS_PENDING;
+
+    (VOID) InterlockedExchangePointer(&Fdo->DevicePowerIrp, Irp);
 
+    IoQueueWorkItem(Fdo->DevicePowerWorkItem,
+                    FdoSetDevicePowerDownWorker,
+                    DelayedWorkQueue,
+                    Fdo);
+
+done:
     return status;
 }
 
@@ -4884,11 +4963,9 @@ FdoSetDevicePower(
           DevicePowerStateName(DeviceState), 
           PowerActionName(PowerAction));
 
-    ASSERT3U(PowerAction, <,  PowerActionShutdown);
-
     if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
-        status = FdoForwardIrpSynchronously(Fdo, Irp);
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        IoSkipCurrentIrpStackLocation(Irp);
+        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
 
         goto done;
     }
@@ -4907,8 +4984,8 @@ done:
 
 __drv_functionClass(REQUEST_POWER_COMPLETE)
 __drv_sameIRQL
-VOID
-FdoRequestSetDevicePowerCompletion(
+static VOID
+FdoRequestDevicePowerUpComplete(
     IN  PDEVICE_OBJECT      DeviceObject,
     IN  UCHAR               MinorFunction,
     IN  POWER_STATE         PowerState,
@@ -4916,112 +4993,204 @@ FdoRequestSetDevicePowerCompletion(
     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. */
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
 }
 
-__drv_requiresIRQL(PASSIVE_LEVEL)
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
 static VOID
-FdoRequestSetDevicePower(
-    IN  PXENBUS_FDO         Fdo,
-    IN  DEVICE_POWER_STATE  DeviceState
+FdoSetSystemPowerUpWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
     )
 {
-    POWER_STATE             PowerState;
-    KEVENT                  Event;
-    NTSTATUS                status;
+    PXENBUS_FDO         Fdo = (PXENBUS_FDO)Context;
+    PIRP                Irp;
+    PIO_STACK_LOCATION  StackLocation;
+    SYSTEM_POWER_STATE  SystemState;
+    POWER_STATE         PowerState;
+    NTSTATUS            status;
 
-    Trace("%s\n", DevicePowerStateName(DeviceState));
+    UNREFERENCED_PARAMETER(DeviceObject);
 
-    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+    Irp = InterlockedExchangePointer(&Fdo->SystemPowerIrp, NULL);
+    ASSERT(Irp != NULL);
 
-    PowerState.DeviceState = DeviceState;
-    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    __FdoSetSystemPowerState(Fdo, PowerSystemHibernate);
+    FdoS4ToS3(Fdo);
+
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+    Info("%s -> %s\n",
+         SystemPowerStateName(__FdoGetSystemPowerState(Fdo)),
+         SystemPowerStateName(SystemState));
+
+    __FdoSetSystemPowerState(Fdo, SystemState);
+
+    PowerState.DeviceState = 
Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
 
     status = PoRequestPowerIrp(Fdo->LowerDeviceObject,
                                IRP_MN_SET_POWER,
                                PowerState,
-                               FdoRequestSetDevicePowerCompletion,
-                               &Event,
+                               FdoRequestDevicePowerUpComplete,
+                               Irp,
                                NULL);
-    ASSERT(NT_SUCCESS(status));
+    /* Whatever happens, we have stopped completion processing for SIrp,
+      to restart SIrp processing, call IoCompleteRequest. */
+    if (!NT_SUCCESS(status))
+        goto fail1;
 
-    (VOID) KeWaitForSingleObject(&Event,
-                                 Executive,
-                                 KernelMode,
-                                 FALSE,
-                                 NULL);
+    return; /* FdoRequestDevicePowerUpComplete 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
-FdoSetSystemPowerUp(
-    IN  PXENBUS_FDO     Fdo,
-    IN  PIRP            Irp
+FdoSetSystemPowerUpComplete(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PIRP            Irp,
+    IN  PVOID           Context
     )
 {
-
+    PXENBUS_FDO         Fdo = (PXENBUS_FDO) Context;
     PIO_STACK_LOCATION  StackLocation;
     SYSTEM_POWER_STATE  SystemState;
-    DEVICE_POWER_STATE  DeviceState;
+    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;
 
-    ASSERT3U(SystemState, <,  __FdoGetSystemPowerState(Fdo));
+    if (SystemState < PowerSystemHibernate &&
+        __FdoGetSystemPowerState(Fdo) >= PowerSystemHibernate) {
 
-    status = FdoForwardIrpSynchronously(Fdo, Irp);
-    if (!NT_SUCCESS(status))
-        goto done;
+        (VOID) InterlockedExchangePointer(&Fdo->SystemPowerIrp, Irp);
 
-    Info("%s: %s -> %s\n",
-         __FdoGetName(Fdo),
-         SystemPowerStateName(__FdoGetSystemPowerState(Fdo)),
-         SystemPowerStateName(SystemState));
+        IoQueueWorkItem(Fdo->SystemPowerWorkItem,
+                        FdoSetSystemPowerUpWorker,
+                        DelayedWorkQueue,
+                        Fdo);
 
-    if (SystemState < PowerSystemHibernate &&
-        __FdoGetSystemPowerState(Fdo) >= PowerSystemHibernate) {
-        __FdoSetSystemPowerState(Fdo, PowerSystemHibernate);
-        FdoS4ToS3(Fdo);
+        goto done; /* Stop completion routine for the moment... */
     }
 
+    Info("%s -> %s\n",
+         SystemPowerStateName(__FdoGetSystemPowerState(Fdo)),
+         SystemPowerStateName(SystemState));
+
     __FdoSetSystemPowerState(Fdo, SystemState);
 
-    DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
-    FdoRequestSetDevicePower(Fdo, DeviceState);
+    PowerState.DeviceState = 
Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
+
+    status = PoRequestPowerIrp(Fdo->LowerDeviceObject,
+                               IRP_MN_SET_POWER,
+                               PowerState,
+                               FdoRequestDevicePowerUpComplete,
+                               Irp,
+                               NULL);
+    /* Whatever happens, we have stopped completion processing for SIrp,
+      to restart SIrp processing, call IoCompleteRequest. */
+    if (!NT_SUCCESS(status))
+        goto fail1;
 
 done:
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return STATUS_MORE_PROCESSING_REQUIRED; /* FdoRequestDevicePowerUpComplete 
will complete the request.*/
 
-    return status;
+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 NTSTATUS
-FdoSetSystemPowerDown(
+FdoSetSystemPowerUp(
     IN  PXENBUS_FDO     Fdo,
     IN  PIRP            Irp
     )
 {
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+    IoSetCompletionRoutine(Irp,
+                           FdoSetSystemPowerUpComplete,
+                           Fdo,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+    return IoCallDriver(Fdo->LowerDeviceObject, Irp);
+}
+
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
+static VOID
+FdoSetSystemPowerDownWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
+    )
+{
+    PXENBUS_FDO         Fdo = (PXENBUS_FDO)Context;
     PIO_STACK_LOCATION  StackLocation;
     SYSTEM_POWER_STATE  SystemState;
-    DEVICE_POWER_STATE  DeviceState;
-    NTSTATUS            status;
+    PIRP                Irp;
+
+    UNREFERENCED_PARAMETER(DeviceObject);
+
+    Irp = InterlockedExchangePointer(&Fdo->SystemPowerIrp, NULL);
+    ASSERT(Irp != NULL);
 
     StackLocation = IoGetCurrentIrpStackLocation(Irp);
     SystemState = StackLocation->Parameters.Power.State.SystemState;
 
-    ASSERT3U(SystemState, >,  __FdoGetSystemPowerState(Fdo));
+    /* Meet preconditions for S3 to S4 */
+    __FdoSetSystemPowerState(Fdo, PowerSystemSleeping3);
+    FdoS3ToS4(Fdo);
+    __FdoSetSystemPowerState(Fdo, SystemState);
 
-    DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
+    IoCopyCurrentIrpStackLocationToNext(Irp); /* Irp has been pended */
+    IoCallDriver(Fdo->LowerDeviceObject, Irp);
+}
 
-    FdoRequestSetDevicePower(Fdo, DeviceState);
+__drv_functionClass(REQUEST_POWER_COMPLETE)
+__drv_sameIRQL
+static VOID
+FdoRequestDevicePowerDownComplete(
+    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;
+    PXENBUS_DX              Dx = 
(PXENBUS_DX)UpperDeviceObject->DeviceExtension;
+    PXENBUS_FDO             Fdo = Dx->Fdo;
+    SYSTEM_POWER_STATE      SystemState = 
StackLocation->Parameters.Power.State.SystemState;
+
+    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 -> %s\n",
          __FdoGetName(Fdo),
@@ -5030,145 +5199,118 @@ FdoSetSystemPowerDown(
 
     if (SystemState >= PowerSystemHibernate &&
         __FdoGetSystemPowerState(Fdo) < PowerSystemHibernate) {
-        __FdoSetSystemPowerState(Fdo, PowerSystemSleeping3);
-        FdoS3ToS4(Fdo);
+
+        (VOID) InterlockedExchangePointer(&Fdo->SystemPowerIrp, Irp);
+
+        IoQueueWorkItem(Fdo->SystemPowerWorkItem,
+                        FdoSetSystemPowerDownWorker,
+                        DelayedWorkQueue,
+                        Fdo);
+        goto done;
     }
 
     __FdoSetSystemPowerState(Fdo, SystemState);
 
-    status = FdoForwardIrpSynchronously(Fdo, Irp);
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    IoCopyCurrentIrpStackLocationToNext(Irp); /* Irp has been pended */
+    IoCallDriver(Fdo->LowerDeviceObject, Irp);
 
-    return status;
+done:
+    return;
 }
 
 static NTSTATUS
-FdoSetSystemPower(
+FdoSetSystemPowerDown(
     IN  PXENBUS_FDO     Fdo,
     IN  PIRP            Irp
     )
 {
     PIO_STACK_LOCATION  StackLocation;
     SYSTEM_POWER_STATE  SystemState;
-    POWER_ACTION        PowerAction;
+    POWER_STATE         PowerState;
     NTSTATUS            status;
 
     StackLocation = IoGetCurrentIrpStackLocation(Irp);
     SystemState = StackLocation->Parameters.Power.State.SystemState;
-    PowerAction = StackLocation->Parameters.Power.ShutdownType;
 
-    Trace("====> (%s:%s)\n",
-          SystemPowerStateName(SystemState), 
-          PowerActionName(PowerAction));
+    ASSERT3U(SystemState, >,  __FdoGetSystemPowerState(Fdo));
 
-    ASSERT3U(PowerAction, <,  PowerActionShutdown);
+    PowerState.DeviceState = 
Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
 
-    if (SystemState == __FdoGetSystemPowerState(Fdo)) {
-        status = FdoForwardIrpSynchronously(Fdo, Irp);
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    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);
 
         goto done;
     }
 
-    status = (SystemState < __FdoGetSystemPowerState(Fdo)) ?
-             FdoSetSystemPowerUp(Fdo, Irp) :
-             FdoSetSystemPowerDown(Fdo, Irp);
+    status = PoRequestPowerIrp(Fdo->LowerDeviceObject,
+                               IRP_MN_SET_POWER,
+                               PowerState,
+                               FdoRequestDevicePowerDownComplete,
+                               Irp,
+                               NULL);
+    if (!NT_SUCCESS(status))
+        goto fail1;
 
 done:
-    Trace("<==== (%s:%s)(%08x)\n",
-          SystemPowerStateName(SystemState), 
-          PowerActionName(PowerAction),
-          status);
-    return status;
-}
-
-static NTSTATUS
-FdoQueryDevicePowerUp(
-    IN  PXENBUS_FDO     Fdo,
-    IN  PIRP            Irp
-    )
-{
-    PIO_STACK_LOCATION  StackLocation;
-    DEVICE_POWER_STATE  DeviceState;
-    NTSTATUS            status;
-
-    StackLocation = IoGetCurrentIrpStackLocation(Irp);
-    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
-
-    ASSERT3U(DeviceState, <,  __FdoGetDevicePowerState(Fdo));
-
-    status = FdoForwardIrpSynchronously(Fdo, Irp);
-
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
     return status;
-}
-
-static NTSTATUS
-FdoQueryDevicePowerDown(
-    IN  PXENBUS_FDO     Fdo,
-    IN  PIRP            Irp
-    )
-{
-    PIO_STACK_LOCATION  StackLocation;
-    DEVICE_POWER_STATE  DeviceState;
-    NTSTATUS            status;
-
-    StackLocation = IoGetCurrentIrpStackLocation(Irp);
-    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
-
-    ASSERT3U(DeviceState, >,  __FdoGetDevicePowerState(Fdo));
-
-    status = FdoForwardIrpSynchronously(Fdo, Irp);
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
+fail1:
+    /* In theory could change IRP status, but are not supposed to fail this 
IRP. */
+    Error("fail1 - but continue IRP processing. (%08x)\n", status);
     return status;
 }
 
 static NTSTATUS
-FdoQueryDevicePower(
+FdoSetSystemPower(
     IN  PXENBUS_FDO     Fdo,
     IN  PIRP            Irp
     )
 {
     PIO_STACK_LOCATION  StackLocation;
-    DEVICE_POWER_STATE  DeviceState;
+    SYSTEM_POWER_STATE  SystemState;
     POWER_ACTION        PowerAction;
     NTSTATUS            status;
 
     StackLocation = IoGetCurrentIrpStackLocation(Irp);
-    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+    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",
-          DevicePowerStateName(DeviceState), 
+          SystemPowerStateName(SystemState),
           PowerActionName(PowerAction));
 
-    ASSERT3U(PowerAction, <,  PowerActionShutdown);
-
-    if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
-        status = FdoForwardIrpSynchronously(Fdo, Irp);
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    if (SystemState == __FdoGetSystemPowerState(Fdo)) {
+        IoCopyCurrentIrpStackLocationToNext(Irp); /* Pended, copy not skip */
+        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
 
         goto done;
     }
 
-    status = (DeviceState < __FdoGetDevicePowerState(Fdo)) ?
-             FdoQueryDevicePowerUp(Fdo, Irp) :
-             FdoQueryDevicePowerDown(Fdo, Irp);
+    status = (SystemState < __FdoGetSystemPowerState(Fdo)) ?
+             FdoSetSystemPowerUp(Fdo, Irp) :
+             FdoSetSystemPowerDown(Fdo, Irp);
 
 done:
     Trace("<==== (%s:%s)(%08x)\n",
-          DevicePowerStateName(DeviceState), 
+          SystemPowerStateName(SystemState),
           PowerActionName(PowerAction),
           status);
+
     return status;
 }
 
 __drv_functionClass(REQUEST_POWER_COMPLETE)
 __drv_sameIRQL
-VOID
-FdoRequestQueryDevicePowerCompletion(
+static VOID
+FdoRequestQuerySystemPowerUpComplete(
     IN  PDEVICE_OBJECT      DeviceObject,
     IN  UCHAR               MinorFunction,
     IN  POWER_STATE         PowerState,
@@ -5176,48 +5318,56 @@ FdoRequestQueryDevicePowerCompletion(
     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));
-
-    KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+    if (!NT_SUCCESS(IoStatus->Status))
+        Irp->IoStatus.Status = IoStatus->Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
 }
 
-__drv_requiresIRQL(PASSIVE_LEVEL)
-static VOID
-FdoRequestQueryDevicePower(
-    IN  PXENBUS_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", DevicePowerStateName(DeviceState));
+    PXENBUS_FDO         Fdo = (PXENBUS_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,
-                               FdoRequestQueryDevicePowerCompletion,
-                               &Event,
+                               FdoRequestQuerySystemPowerUpComplete,
+                               Irp,
                                NULL);
-    ASSERT(NT_SUCCESS(status));
+    if (!NT_SUCCESS(status))
+        goto fail1;
 
-    (VOID) KeWaitForSingleObject(&Event,
-                                 Executive,
-                                 KernelMode,
-                                 FALSE,
-                                 NULL);
+    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 NTSTATUS
@@ -5226,29 +5376,50 @@ FdoQuerySystemPowerUp(
     IN  PIRP            Irp
     )
 {
+    IoMarkIrpPending(Irp); /* Must mark IRP pending because we want to 
complete it *after* completion routine. */
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+    IoSetCompletionRoutine(Irp,
+                           FdoQuerySystemPowerUpComplete,
+                           Fdo,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+    return IoCallDriver(Fdo->LowerDeviceObject, Irp);
+}
 
-    PIO_STACK_LOCATION  StackLocation;
-    SYSTEM_POWER_STATE  SystemState;
-    DEVICE_POWER_STATE  DeviceState;
-    NTSTATUS            status;
-
-    StackLocation = IoGetCurrentIrpStackLocation(Irp);
-    SystemState = StackLocation->Parameters.Power.State.SystemState;
+__drv_functionClass(REQUEST_POWER_COMPLETE)
+__drv_sameIRQL
+static VOID
+FdoRequestQuerySystemPowerDownComplete(
+    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;
+    PXENBUS_DX              Dx = 
(PXENBUS_DX)UpperDeviceObject->DeviceExtension;
+    PXENBUS_FDO             Fdo = Dx->Fdo;
 
-    ASSERT3U(SystemState, <,  __FdoGetSystemPowerState(Fdo));
+    UNREFERENCED_PARAMETER(DeviceObject);
+    UNREFERENCED_PARAMETER(MinorFunction);
+    UNREFERENCED_PARAMETER(PowerState);
 
-    status = FdoForwardIrpSynchronously(Fdo, Irp);
-    if (!NT_SUCCESS(status))
-        goto done;
+    if (!NT_SUCCESS(IoStatus->Status))
+        goto fail1;
 
-    DeviceState = Fdo->LowerDeviceCapabilities.DeviceState[SystemState];
+    IoCopyCurrentIrpStackLocationToNext(Irp); /* Irp has been pended. */
+    IoCallDriver(Fdo->LowerDeviceObject, Irp);
 
-    FdoRequestQueryDevicePower(Fdo, DeviceState);
+    return;
 
-done:
+fail1:
+    Error("fail1 (%08x)\n", IoStatus->Status);
+    Irp->IoStatus.Status = IoStatus->Status;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-    return status;
 }
 
 static NTSTATUS
@@ -5259,7 +5430,7 @@ FdoQuerySystemPowerDown(
 {
     PIO_STACK_LOCATION  StackLocation;
     SYSTEM_POWER_STATE  SystemState;
-    DEVICE_POWER_STATE  DeviceState;
+    POWER_STATE         PowerState;
     NTSTATUS            status;
 
     StackLocation = IoGetCurrentIrpStackLocation(Irp);
@@ -5267,11 +5438,24 @@ 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,
+                               FdoRequestQuerySystemPowerDownComplete,
+                               Irp,
+                               NULL);
+    if (!NT_SUCCESS(status))
+        goto fail1;
 
-    status = FdoForwardIrpSynchronously(Fdo, Irp);
+    IoMarkIrpPending(Irp);
+    return STATUS_PENDING;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    Irp->IoStatus.Status = status;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
     return status;
@@ -5296,11 +5480,9 @@ FdoQuerySystemPower(
           SystemPowerStateName(SystemState), 
           PowerActionName(PowerAction));
 
-    ASSERT3U(PowerAction, <,  PowerActionShutdown);
-
     if (SystemState == __FdoGetSystemPowerState(Fdo)) {
-        status = FdoForwardIrpSynchronously(Fdo, Irp);
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        IoSkipCurrentIrpStackLocation(Irp);
+        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
 
         goto done;
     }
@@ -5319,117 +5501,57 @@ done:
 }
 
 static NTSTATUS
-FdoDevicePower(
-    IN  PXENBUS_THREAD  Self,
-    IN  PVOID           Context
+FdoDispatchDevicePower(
+    IN  PXENBUS_FDO     Fdo,
+    IN  PIRP            Irp
     )
 {
-    PXENBUS_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();
-
-        StackLocation = IoGetCurrentIrpStackLocation(Irp);
-        MinorFunction = StackLocation->MinorFunction;
+    PIO_STACK_LOCATION  StackLocation;
+    NTSTATUS            status;
 
-        switch (StackLocation->MinorFunction) {
-        case IRP_MN_SET_POWER:
-            (VOID) FdoSetDevicePower(Fdo, Irp);
-            break;
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
 
-        case IRP_MN_QUERY_POWER:
-            (VOID) FdoQueryDevicePower(Fdo, Irp);
-            break;
+    switch (StackLocation->MinorFunction) {
+    case IRP_MN_SET_POWER:
+        status = FdoSetDevicePower(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  PXENBUS_THREAD  Self,
-    IN  PVOID           Context
+FdoDispatchSystemPower(
+    IN  PXENBUS_FDO     Fdo,
+    IN  PIRP            Irp
     )
 {
-    PXENBUS_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 NTSTATUS
@@ -5439,55 +5561,21 @@ FdoDispatchPower(
     )
 {
     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 = FdoDispatchDevicePower(Fdo, Irp);
         break;
 
     case SystemPowerState:
-        IoMarkIrpPending(Irp);
-
-        ASSERT3P(Fdo->SystemPowerIrp, ==, NULL);
-        Fdo->SystemPowerIrp = Irp;
-        KeMemoryBarrier();
-
-        ThreadWake(Fdo->SystemPowerThread);
-
-        status = STATUS_PENDING;
+        status = FdoDispatchSystemPower(Fdo, Irp);
         break;
 
     default:
@@ -5496,10 +5584,10 @@ FdoDispatchPower(
         break;
     }
 
-done:
     return status;
 }
 
+
 static NTSTATUS
 FdoDispatchDefault(
     IN  PXENBUS_FDO Fdo,
@@ -5748,12 +5836,12 @@ FdoCreate(
     Fdo->LowerDeviceObject = IoAttachDeviceToDeviceStack(FunctionDeviceObject,
                                                          PhysicalDeviceObject);
 
-    status = ThreadCreate(FdoSystemPower, Fdo, &Fdo->SystemPowerThread);
-    if (!NT_SUCCESS(status))
+    Fdo->SystemPowerWorkItem = IoAllocateWorkItem(FunctionDeviceObject);
+    if (Fdo->SystemPowerWorkItem == NULL)
         goto fail3;
 
-    status = ThreadCreate(FdoDevicePower, Fdo, &Fdo->DevicePowerThread);
-    if (!NT_SUCCESS(status))
+    Fdo->DevicePowerWorkItem = IoAllocateWorkItem(FunctionDeviceObject);
+    if (Fdo->DevicePowerWorkItem == NULL)
         goto fail4;
 
     status = FdoAcquireLowerBusInterface(Fdo);
@@ -5992,17 +6080,15 @@ 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");
 
@@ -6117,13 +6203,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/xenbus/pdo.c b/src/xenbus/pdo.c
index 3f1e4c5..9163923 100644
--- a/src/xenbus/pdo.c
+++ b/src/xenbus/pdo.c
@@ -58,9 +58,9 @@
 struct _XENBUS_PDO {
     PXENBUS_DX                  Dx;
 
-    PXENBUS_THREAD              SystemPowerThread;
+    PIO_WORKITEM                SystemPowerWorkItem;
     PIRP                        SystemPowerIrp;
-    PXENBUS_THREAD              DevicePowerThread;
+    PIO_WORKITEM                DevicePowerWorkItem;
     PIRP                        DevicePowerIrp;
 
     PXENBUS_FDO                 Fdo;
@@ -1695,26 +1695,31 @@ PdoDispatchPnp(
     return status;
 }
 
-static NTSTATUS
-PdoSetDevicePower(
-    IN  PXENBUS_PDO     Pdo,
-    IN  PIRP            Irp
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
+static VOID
+PdoSetDevicePowerWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
     )
 {
+    PXENBUS_PDO         Pdo = (PXENBUS_PDO) Context;
+    PIRP                Irp;
+    NTSTATUS            status;
     PIO_STACK_LOCATION  StackLocation;
     DEVICE_POWER_STATE  DeviceState;
     POWER_ACTION        PowerAction;
 
+    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)\n",
-          DevicePowerStateName(DeviceState), 
-          PowerActionName(PowerAction));
-
-    ASSERT3U(PowerAction, <, PowerActionShutdown);
-
+    status = STATUS_SUCCESS;
     if (__PdoGetDevicePowerState(Pdo) > DeviceState) {
         Trace("%s: POWERING UP: %s -> %s\n",
               __PdoGetName(Pdo),
@@ -1722,7 +1727,7 @@ PdoSetDevicePower(
               DevicePowerStateName(DeviceState));
 
         ASSERT3U(DeviceState, ==, PowerDeviceD0);
-        PdoD3ToD0(Pdo);
+        status = PdoD3ToD0(Pdo);
     } else if (__PdoGetDevicePowerState(Pdo) < DeviceState) {
         Trace("%s: POWERING DOWN: %s -> %s\n",
               __PdoGetName(Pdo),
@@ -1733,76 +1738,76 @@ PdoSetDevicePower(
         PdoD0ToD3(Pdo);
     }
 
+    if(NT_SUCCESS(status))
+        goto done;
+
+    Error("fail1 (%08x)\n", status);
+    /* TODO - Consider cycling device power at some later point?
+       Need PPO to retry SIRP -> DIRP */
+
+done:
+    /* Cannot fail the IRP at this point, keep going. */
     Irp->IoStatus.Status = STATUS_SUCCESS;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
     Trace("<==== (%s:%s)\n",
           DevicePowerStateName(DeviceState), 
           PowerActionName(PowerAction));
-
-    return STATUS_SUCCESS;
 }
 
 static NTSTATUS
-PdoDevicePower(
-    IN  PXENBUS_THREAD  Self,
-    IN  PVOID           Context
+PdoSetDevicePower(
+    IN  PXENBUS_PDO     Pdo,
+    IN  PIRP            Irp
     )
 {
-    PXENBUS_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;
 
-        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",
+          DevicePowerStateName(DeviceState),
+          PowerActionName(PowerAction));
 
-        if (Irp == NULL)
-            continue;
+    IoMarkIrpPending(Irp);
 
-        Pdo->DevicePowerIrp = NULL;
-        KeMemoryBarrier();
+    (VOID) InterlockedExchangePointer(&Pdo->DevicePowerIrp, Irp);
 
-        (VOID) PdoSetDevicePower(Pdo, Irp);
-    }
+    IoQueueWorkItem(Pdo->DevicePowerWorkItem,
+                    PdoSetDevicePowerWorker,
+                    DelayedWorkQueue,
+                    Pdo);
 
-    return STATUS_SUCCESS;
+    return STATUS_PENDING;
 }
 
-static NTSTATUS
-PdoSetSystemPower(
-    IN  PXENBUS_PDO     Pdo,
-    IN  PIRP            Irp
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_sameIRQL
+static VOID
+PdoSetSystemPowerWorker(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PVOID           Context
     )
 {
+    PXENBUS_PDO         Pdo = (PXENBUS_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)\n",
-          SystemPowerStateName(SystemState), 
-          PowerActionName(PowerAction));
-
-    ASSERT3U(PowerAction, <, PowerActionShutdown);
-
     if (__PdoGetSystemPowerState(Pdo) > SystemState) {
         if (SystemState < PowerSystemHibernate &&
             __PdoGetSystemPowerState(Pdo) >= PowerSystemHibernate) {
@@ -1836,52 +1841,40 @@ PdoSetSystemPower(
     Trace("<==== (%s:%s)\n",
           SystemPowerStateName(SystemState), 
           PowerActionName(PowerAction));
-
-    return STATUS_SUCCESS;
 }
 
 static NTSTATUS
-PdoSystemPower(
-    IN  PXENBUS_THREAD  Self,
-    IN  PVOID           Context
+PdoSetSystemPower(
+    IN  PXENBUS_PDO     Pdo,
+    IN  PIRP            Irp
     )
 {
-    PXENBUS_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;
 
-        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",
+          SystemPowerStateName(SystemState),
+          PowerActionName(PowerAction));
 
-        if (Irp == NULL)
-            continue;
+    IoMarkIrpPending(Irp);
 
-        Pdo->SystemPowerIrp = NULL;
-        KeMemoryBarrier();
+    (VOID) InterlockedExchangePointer(&Pdo->SystemPowerIrp, Irp);
 
-        (VOID) PdoSetSystemPower(Pdo, Irp);
-    }
+    IoQueueWorkItem(Pdo->SystemPowerWorkItem,
+                    PdoSetSystemPowerWorker,
+                    DelayedWorkQueue,
+                    Pdo);
 
-    return STATUS_SUCCESS;
+    return STATUS_PENDING;
 }
 
 static NTSTATUS
-PdoSetPower(
+PdoDispatchSetPower(
     IN  PXENBUS_PDO     Pdo,
     IN  PIRP            Irp
     )
@@ -1895,38 +1888,13 @@ PdoSetPower(
     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:
@@ -1935,25 +1903,6 @@ PdoSetPower(
         break;
     }
 
-done:
-    return status;
-}
-
-static NTSTATUS
-PdoQueryPower(
-    IN  PXENBUS_PDO Pdo,
-    IN  PIRP        Irp
-    )
-{
-    NTSTATUS        status;
-
-    UNREFERENCED_PARAMETER(Pdo);
-
-    status = STATUS_SUCCESS;
-
-    Irp->IoStatus.Status = status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
     return status;
 }
 
@@ -1972,14 +1921,11 @@ PdoDispatchPower(
 
     switch (StackLocation->MinorFunction) {
     case IRP_MN_SET_POWER:
-        status = PdoSetPower(Pdo, Irp);
-        break;
-
-    case IRP_MN_QUERY_POWER:
-        status = PdoQueryPower(Pdo, Irp);
+        status = PdoDispatchSetPower(Pdo, Irp);
         break;
 
     default:
+        /* TODO - Always complete with status success?? */
         status = Irp->IoStatus.Status;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
         break;
@@ -2093,12 +2039,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, Name);
@@ -2135,16 +2081,14 @@ fail5:
     Pdo->Ejectable = FALSE;
     Pdo->Removable = FALSE;
 
-    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");
@@ -2198,13 +2142,11 @@ PdoDestroy(
     Pdo->Ejectable = FALSE;
     Pdo->Removable = FALSE;
 
-    ThreadAlert(Pdo->DevicePowerThread);
-    ThreadJoin(Pdo->DevicePowerThread);
-    Pdo->DevicePowerThread = NULL;
-    
-    ThreadAlert(Pdo->SystemPowerThread);
-    ThreadJoin(Pdo->SystemPowerThread);
-    Pdo->SystemPowerThread = NULL;
+    IoFreeWorkItem(Pdo->DevicePowerWorkItem);
+    Pdo->DevicePowerWorkItem = NULL;
+
+    IoFreeWorkItem(Pdo->SystemPowerWorkItem);
+    Pdo->SystemPowerWorkItem = NULL;
 
     Pdo->Fdo = NULL;
     Pdo->Dx = NULL;
-- 
2.41.0.windows.3




 


Rackspace

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