[IBBUS,HW] add standby/hibernation support to IBBUS. [mlnx: 4750]
authorleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Mon, 26 Oct 2009 09:35:50 +0000 (09:35 +0000)
committerleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Mon, 26 Oct 2009 09:35:50 +0000 (09:35 +0000)
Mellanox HW doesn't support neither standby nor hibernation.
To simulate such support, low-level driver resets HCA on power down and starts it up on power up.
IBBUS, continuing to work with HCA, produces BSODs.

This patch deregisters HCA from IBAL on power down and re-registers it on power up.

git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@2507 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

core/bus/kernel/bus_driver.h
core/bus/kernel/bus_iou_mgr.c
core/bus/kernel/bus_pnp.c
core/bus/kernel/bus_port_mgr.c
hw/mlx4/kernel/bus/drv/drv.c
hw/mlx4/kernel/hca/drv.c
hw/mthca/kernel/hca_pnp.c

index 08fc71f..ff20ee0 100644 (file)
@@ -125,6 +125,17 @@ typedef struct _bus_fdo_ext
 \r
        struct _bus_filter_instance *bus_filter;\r
 \r
+       /* flag, indicating that FDO resources have been released */\r
+       boolean_t                               ca_registered;\r
+       /* current device power state */\r
+       DEVICE_POWER_STATE              device_power_state;\r
+       /* current system  power state */\r
+       SYSTEM_POWER_STATE              system_power_state;\r
+       /* work item for power operations */\r
+       PIO_WORKITEM                    p_po_work_item;\r
+       /* current PnP state */\r
+       PNP_DEVICE_STATE                pnp_state; /* state for PnP Manager */\r
+\r
 }      bus_fdo_ext_t;\r
 \r
 \r
index d711ee6..38fef0e 100644 (file)
@@ -1658,7 +1658,9 @@ iou_set_power(
 \r
        if ((p_io_stack->Parameters.Power.Type == SystemPowerState) &&\r
                (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate ||\r
-               p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 ))\r
+               p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 || \r
+               p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping2 || \r
+               p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping3 ))\r
        {\r
                BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj));\r
                p_ext->b_hibernating = TRUE;\r
index 65a024e..bb4088d 100644 (file)
@@ -49,6 +49,7 @@
 #include "iba/ib_cm_ifc.h"\r
 #include "al_cm_cep.h"\r
 #include "al_mgr.h"\r
+#include "bus_ev_log.h"\r
 \r
 \r
 /* Interface names are generated by IoRegisterDeviceInterface. */\r
@@ -112,6 +113,13 @@ __query_cm_ifc(
        IN                              DEVICE_OBJECT* const            p_dev_obj,\r
        IN                              IO_STACK_LOCATION* const        p_io_stack );\r
 \r
+static NTSTATUS\r
+fdo_query_pnp_state(\r
+       IN                              DEVICE_OBJECT* const            p_dev_obj,\r
+       IN                              IRP* const                                      p_irp, \r
+               OUT                     cl_irp_action_t* const          p_action );\r
+\r
+\r
 static NTSTATUS\r
 fdo_query_interface(\r
        IN                              DEVICE_OBJECT* const            p_dev_obj,\r
@@ -150,7 +158,7 @@ static const cl_vfptr_pnp_po_t              vfptr_fdo_pnp = {
        cl_do_sync_pnp,\r
        cl_irp_skip,\r
        fdo_query_capabilities,\r
-       cl_irp_skip,\r
+       fdo_query_pnp_state,\r
        cl_irp_skip,\r
        cl_do_sync_pnp,\r
        fdo_query_bus_relations,\r
@@ -245,8 +253,7 @@ bus_add_device(
        }\r
 \r
        p_ext = p_dev_obj->DeviceExtension;\r
-       p_ext->n_al_ifc_ref = 0;\r
-       p_ext->n_ci_ifc_ref = 0;\r
+       cl_memclr( p_ext, sizeof(bus_fdo_ext_t) );\r
 \r
        p_next_do = IoAttachDeviceToDeviceStack( p_dev_obj, p_pdo );\r
        if( !p_next_do )\r
@@ -383,6 +390,53 @@ __get_ifc(
        return status;\r
 }\r
 \r
+\r
+static NTSTATUS\r
+__register_ca(\r
+       IN                                      DEVICE_OBJECT* const    p_dev_obj\r
+       )\r
+{\r
+       NTSTATUS                status;\r
+       bus_fdo_ext_t   *p_ext;\r
+       ib_api_status_t ib_status;\r
+       bus_filter_t    *p_bfi;\r
+\r
+       BUS_ENTER( BUS_DBG_PNP );\r
+\r
+       p_ext = p_dev_obj->DeviceExtension;\r
+       p_bfi = p_ext->bus_filter;\r
+\r
+       /* get HCA verbs interface */\r
+       status = __get_ifc( p_dev_obj, &GUID_RDMA_INTERFACE_VERBS,\r
+                                               sizeof(RDMA_INTERFACE_VERBS), \r
+                                               VerbsVersion(VERBS_MAJOR_VER, VERBS_MINOR_VER), \r
+                                               p_ext, (PINTERFACE)&p_ext->hca_ifc );\r
+       if( !NT_SUCCESS( status ) ) \r
+       {\r
+               BUS_TRACE_EXIT(BUS_DBG_PNP,\r
+                       ("Getting MLX4 BUS interface failed: status=0x%x\n", status));\r
+               return STATUS_UNSUCCESSFUL;\r
+       }\r
+       p_ext->hca_ifc_taken = TRUE;\r
+\r
+       /* bind BFI to HCA by CA GUID. Have to be before ib_register_ca */\r
+       p_bfi->ca_guid = p_ext->hca_ifc.Verbs.guid;\r
+\r
+       /* register HCA */\r
+       ib_status = ib_register_ca( &p_ext->hca_ifc.Verbs, p_ext->cl_ext.p_pdo, p_dev_obj );\r
+       if( ib_status != IB_SUCCESS )\r
+       {\r
+               BUS_TRACE_EXIT( BUS_DBG_ERROR, ("ib_register_ca returned %s.\n",\r
+                       ib_get_err_str(ib_status)) );\r
+               return STATUS_UNSUCCESSFUL;\r
+       }\r
+       BUS_TRACE_EXIT(BUS_DBG_PNP, ("%s bound to CA guid %I64x\n",\r
+               p_bfi->whoami,p_bfi->ca_guid));\r
+\r
+       p_ext->ca_registered = TRUE;\r
+       return status;\r
+}\r
+\r
 static NTSTATUS\r
 fdo_start(\r
        IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
@@ -399,6 +453,7 @@ fdo_start(
 \r
        p_ext = p_dev_obj->DeviceExtension;\r
        p_bfi = p_ext->bus_filter;\r
+       ASSERT( !p_ext->ca_registered );\r
 \r
        /* Handled on the way up. */\r
        status = cl_do_sync_pnp( p_dev_obj, p_irp, p_action );\r
@@ -408,6 +463,7 @@ fdo_start(
                        ("Lower drivers failed IRP_MN_START_DEVICE.\n") );\r
                return status;\r
        }\r
+       p_ext->device_power_state = PowerDeviceD0;\r
 \r
        lock_control_event();\r
        if ( !gp_async_proc_mgr ) {\r
@@ -444,6 +500,11 @@ fdo_start(
                return STATUS_UNSUCCESSFUL;\r
        }\r
 \r
+       /* start IBAL */\r
+       status = __register_ca( p_dev_obj );\r
+       if( !NT_SUCCESS( status ) )\r
+               return status;\r
+\r
        if ( AL_init_here ) {\r
                status = IoSetDeviceInterfaceState( &al_ifc_name, TRUE );\r
                ASSERT( NT_SUCCESS( status ) );\r
@@ -455,33 +516,9 @@ fdo_start(
                ASSERT( NT_SUCCESS( status ) );\r
        }\r
 \r
-       /* get HCA verbs interface */\r
-       status = __get_ifc( p_dev_obj, &GUID_RDMA_INTERFACE_VERBS,\r
-                                               sizeof(RDMA_INTERFACE_VERBS), \r
-                                               VerbsVersion(VERBS_MAJOR_VER, VERBS_MINOR_VER), \r
-                                               p_ext, (PINTERFACE)&p_ext->hca_ifc );\r
-       if( !NT_SUCCESS( status ) ) \r
-       {\r
-               BUS_TRACE_EXIT(BUS_DBG_PNP,\r
-                       ("Getting MLX4 BUS interface failed: status=0x%x\n", status));\r
-               return STATUS_UNSUCCESSFUL;\r
-       }\r
-       p_ext->hca_ifc_taken = TRUE;\r
-\r
-       /* bind BFI to HCA by CA GUID. Have to be before ib_register_ca */\r
-       p_bfi->ca_guid = p_ext->hca_ifc.Verbs.guid;\r
+       CL_PRINT_TO_EVENT_LOG( p_dev_obj, EVENT_IBBUS_ANY_INFO,\r
+               ("IBBUS started \n" ));\r
 \r
-       /* register HCA */\r
-       ib_status = ib_register_ca( &p_ext->hca_ifc.Verbs, p_ext->cl_ext.p_pdo, p_dev_obj );\r
-       if( ib_status != IB_SUCCESS )\r
-       {\r
-               BUS_TRACE_EXIT( BUS_DBG_ERROR, ("ib_register_ca returned %s.\n",\r
-                       ib_get_err_str(ib_status)) );\r
-               return STATUS_UNSUCCESSFUL;\r
-       }\r
-\r
-       BUS_TRACE_EXIT(BUS_DBG_PNP, ("%s bound to CA guid %I64x\n",\r
-                                                                       p_bfi->whoami,p_bfi->ca_guid));\r
        return status;\r
 }\r
 \r
@@ -537,6 +574,40 @@ fdo_query_remove(
 }\r
 \r
 \r
+static void\r
+__deregister_ca(\r
+       IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
+{\r
+       bus_fdo_ext_t   *p_ext;\r
+       bus_filter_t    *p_bfi;\r
+       ib_api_status_t ib_status;\r
+\r
+       BUS_ENTER( BUS_DBG_PNP );\r
+\r
+       p_ext = p_dev_obj->DeviceExtension;\r
+       p_bfi = p_ext->bus_filter;\r
+\r
+       if ( !p_ext->ca_registered )\r
+               return;\r
+       p_ext->ca_registered = FALSE;\r
+\r
+       //TODO: Fail outstanding I/O operations.\r
+\r
+       ib_status = ib_deregister_ca( p_ext->hca_ifc.Verbs.guid );\r
+       if( ib_status != IB_SUCCESS ) {\r
+               BUS_PRINT( BUS_DBG_ERROR, ("ib_deregister_ca returned %s.\n",\r
+                       ib_get_err_str(ib_status)) );\r
+       }\r
+\r
+       if ( p_ext->hca_ifc_taken ) {\r
+               p_ext->hca_ifc.InterfaceHeader.InterfaceDereference(\r
+                       p_ext->hca_ifc.InterfaceHeader.Context);\r
+               p_ext->hca_ifc_taken = FALSE;\r
+       }\r
+\r
+       BUS_EXIT( BUS_DBG_PNP );\r
+}\r
+\r
 /*\r
  * This function gets called after releasing the remove lock and waiting\r
  * for all other threads to release the lock.  No more modifications will\r
@@ -550,7 +621,6 @@ fdo_release_resources(
        NTSTATUS                status;\r
        bus_filter_t    *p_bfi;\r
        int                             ic;\r
-       ib_api_status_t ib_status;\r
 \r
        BUS_ENTER( BUS_DBG_PNP );\r
 \r
@@ -560,13 +630,7 @@ fdo_release_resources(
        p_bfi = p_ext->bus_filter;\r
        CL_ASSERT( p_bfi );\r
 \r
-       //TODO: Fail outstanding I/O operations.\r
-\r
-       ib_status = ib_deregister_ca( p_ext->hca_ifc.Verbs.guid );\r
-       if( ib_status != IB_SUCCESS ) {\r
-               BUS_PRINT( BUS_DBG_ERROR, ("ib_deregister_ca returned %s.\n",\r
-                       ib_get_err_str(ib_status)) );\r
-       }\r
+       __deregister_ca( p_dev_obj );\r
 \r
        if ( p_bfi->p_port_mgr )\r
                cl_obj_destroy( p_bfi->p_port_mgr_obj );\r
@@ -574,6 +638,9 @@ fdo_release_resources(
        if ( p_bfi->p_iou_mgr )\r
                cl_obj_destroy( p_bfi->p_iou_mgr_obj );\r
 \r
+#if 0\r
+       // IBAL has no right to work with CA after it deregister.\r
+       // So there is no need to release interface only after IBAL cleanup\r
 \r
        /* if not last HCA then release IFC reference, otherwise release IFC after\r
         * IBAL has shutdown; keep the HCA present until IBAL is terminated.\r
@@ -583,6 +650,7 @@ fdo_release_resources(
                        p_ext->hca_ifc.InterfaceHeader.Context);\r
                p_ext->hca_ifc_taken = FALSE;\r
        }\r
+#endif \r
 \r
        BUS_TRACE( BUS_DBG_PNP, ("Releasing BusFilter %s\n", p_bfi->whoami ));\r
        if (p_bfi) {\r
@@ -623,6 +691,10 @@ fdo_release_resources(
 \r
        CL_ASSERT( !gp_async_proc_mgr && !gp_async_pnp_mgr && !gp_al_mgr );\r
 \r
+#if 0\r
+               // IBAL has no right to work with CA after it deregister.\r
+               // So there is no need to release interface only after IBAL cleanup\r
+       \r
        /* AL needs the HCA to stick around until AL cleanup has completed.\r
         * Now that it's done, let the HCA fade away.\r
         */\r
@@ -631,6 +703,7 @@ fdo_release_resources(
                        p_ext->hca_ifc.InterfaceHeader.Context);\r
                p_ext->hca_ifc_taken = FALSE;\r
        }\r
+#endif \r
 \r
        BUS_EXIT( BUS_DBG_PNP );\r
 }\r
@@ -1082,6 +1155,26 @@ __query_cm_ifc(
        return STATUS_SUCCESS;\r
 }\r
 \r
+static NTSTATUS\r
+fdo_query_pnp_state(\r
+       IN                              DEVICE_OBJECT* const            p_dev_obj,\r
+       IN                              IRP* const                                      p_irp, \r
+               OUT                     cl_irp_action_t* const          p_action )\r
+{\r
+       bus_fdo_ext_t           *p_ext;\r
+\r
+       BUS_ENTER( BUS_DBG_PNP );\r
+\r
+       p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension;\r
+\r
+       p_irp->IoStatus.Information |= p_ext->pnp_state;\r
+\r
+       *p_action = IrpSkip;\r
+\r
+       BUS_EXIT( BUS_DBG_PNP );\r
+       return STATUS_SUCCESS;;\r
+}\r
+\r
 \r
 static NTSTATUS\r
 fdo_query_interface(\r
@@ -1153,7 +1246,9 @@ __fdo_query_power(
                switch( p_io_stack->Parameters.Power.State.SystemState )\r
                {\r
                        case PowerSystemHibernate:\r
-                       case PowerSystemSleeping1:      // STANDBY support\r
+                       case PowerSystemSleeping1:      // STANDBY support\r
+                       case PowerSystemSleeping2:      // STANDBY support\r
+                       case PowerSystemSleeping3:      // STANDBY support\r
                        case PowerSystemWorking:\r
                        case PowerSystemShutdown:\r
                                break;\r
@@ -1188,91 +1283,187 @@ __fdo_query_power(
 }\r
 \r
 \r
+\r
+/* Work item callback to handle DevicePowerD0 IRPs at passive level. */\r
+\r
 static void\r
-__request_power_completion(\r
-       IN                              DEVICE_OBJECT                           *p_dev_obj,\r
-       IN                              UCHAR                                           minor_function,\r
-       IN                              POWER_STATE                                     power_state,\r
-       IN                              void                                            *context,\r
-       IN                              IO_STATUS_BLOCK                         *p_io_status )\r
+__device_power_up_completion_workItem(\r
+       IN                              DEVICE_OBJECT*                          p_dev_obj,\r
+       IN                              void*                                           context )\r
 {\r
+       NTSTATUS                        status;\r
+       IO_STACK_LOCATION       *p_io_stack;\r
+       bus_fdo_ext_t           *p_ext;\r
        IRP                                     *p_irp;\r
-       cl_pnp_po_ext_t         *p_ext;\r
-\r
-       BUS_ENTER( BUS_DBG_PNP );\r
+       POWER_STATE                     power_state;\r
 \r
-       UNUSED_PARAM( minor_function );\r
-       UNUSED_PARAM( power_state );\r
+       BUS_ENTER( BUS_DBG_POWER );\r
 \r
+       p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension;\r
        p_irp = (IRP*)context;\r
-       p_ext = p_dev_obj->DeviceExtension;\r
+       p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+       IoFreeWorkItem( p_ext->p_po_work_item );\r
+       p_ext->p_po_work_item = NULL;\r
 \r
-       /* Propagate the device IRP status to the system IRP status. */\r
-       p_irp->IoStatus.Status = p_io_status->Status;\r
+       /* re-register CA */\r
+       BUS_PRINT( BUS_DBG_POWER, \r
+               ("***** re-register CA, IRQL %d\n", KeGetCurrentIrql()));\r
 \r
-       /* Continue Power IRP processing. */\r
+       status = __register_ca( p_dev_obj );\r
+       if( !NT_SUCCESS( status ) ) {\r
+               BUS_PRINT( BUS_DBG_POWER, \r
+                       ("!!! __register_ca failed (%#x) \n", status));\r
+               goto err_fdo_start;\r
+       }\r
+\r
+       p_ext->device_power_state = p_io_stack->Parameters.Power.State.DeviceState;\r
+       power_state = PoSetPowerState( p_dev_obj, DevicePowerState,\r
+               p_io_stack->Parameters.Power.State );\r
+\r
+       BUS_PRINT( BUS_DBG_POWER, \r
+               ("PoSetPowerState: old state %d, new state to %d\n", \r
+               power_state.DeviceState, p_ext->device_power_state ));\r
+\r
+       CL_PRINT_TO_EVENT_LOG( p_dev_obj, EVENT_IBBUS_ANY_WARN,\r
+               ("Power increased to: device %d, system %d.\n",\r
+               (int)p_ext->device_power_state, (int)p_ext->system_power_state));\r
+\r
+       goto exit;\r
+\r
+err_fdo_start:\r
+       /* Flag device as having failed. */\r
+       p_ext->pnp_state |= PNP_DEVICE_FAILED;\r
+       IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
+exit:\r
        PoStartNextPowerIrp( p_irp );\r
        IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
-       IoReleaseRemoveLock( &p_ext->remove_lock, p_irp );\r
-       BUS_EXIT( BUS_DBG_PNP );\r
+       IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+       BUS_EXIT( BUS_DBG_POWER );\r
 }\r
 \r
 \r
 /*NOTE: Completion routines must NEVER be pageable. */\r
 static NTSTATUS\r
-__set_power_completion(\r
+__device_power_up_completion(\r
        IN                              DEVICE_OBJECT                           *p_dev_obj,\r
        IN                              IRP                                                     *p_irp,\r
        IN                              void                                            *context )\r
 {\r
-       NTSTATUS                        status;\r
-       POWER_STATE                     state;\r
+       NTSTATUS                        status = STATUS_SUCCESS;\r
        bus_fdo_ext_t           *p_ext;\r
        IO_STACK_LOCATION       *p_io_stack;\r
 \r
-       BUS_ENTER( BUS_DBG_PNP );\r
+       BUS_ENTER( BUS_DBG_POWER );\r
 \r
        UNUSED_PARAM( context );\r
 \r
-       p_ext = p_dev_obj->DeviceExtension;\r
+       p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension;\r
        p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
 \r
-       if( !NT_SUCCESS( p_irp->IoStatus.Status ) )\r
-       {\r
+       if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) {\r
+               BUS_PRINT( BUS_DBG_POWER, \r
+                       ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n",\r
+                       p_irp->IoStatus.Status));\r
+               status =  STATUS_SUCCESS;\r
                PoStartNextPowerIrp( p_irp );\r
-               IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
-               BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
-                       ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n",\r
-                       p_irp->IoStatus.Status) );\r
-               return STATUS_SUCCESS;\r
+               goto release;\r
        }\r
 \r
-       state.DeviceState = \r
-               p_ext->po_state[p_io_stack->Parameters.Power.State.SystemState];\r
-\r
-       /*\r
-        * Send a device power IRP to our devnode.  Using our device object will\r
-        * only work on win2k and other NT based systems.\r
-        */\r
-       status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state,\r
-               __request_power_completion, p_irp, NULL );\r
-\r
-       if( status != STATUS_PENDING )\r
-       {\r
+       /* Process in a work item to allow blocking. */\r
+       ASSERT( !p_ext->p_po_work_item );\r
+       p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
+       if( !p_ext->p_po_work_item ) {\r
+               BUS_PRINT( BUS_DBG_POWER, \r
+                       ("Failed to allocate work item.\n" ));\r
+               status = STATUS_SUCCESS;\r
+               p_ext->pnp_state |= PNP_DEVICE_FAILED;\r
+               IoInvalidateDeviceState( p_ext->cl_ext.p_pdo );\r
                PoStartNextPowerIrp( p_irp );\r
-               /* Propagate the failure. */\r
-               p_irp->IoStatus.Status = status;\r
-               IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
-               IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
-               BUS_TRACE( BUS_DBG_ERROR,\r
-                       ("PoRequestPowerIrp returned %08x.\n", status) );\r
+               goto release;\r
        }\r
 \r
-       BUS_EXIT( BUS_DBG_PNP );\r
-       return STATUS_MORE_PROCESSING_REQUIRED;\r
+       /* Process in work item callback. */\r
+       IoMarkIrpPending( p_irp );\r
+       IoQueueWorkItem( p_ext->p_po_work_item, \r
+               __device_power_up_completion_workItem, DelayedWorkQueue, p_irp );\r
+       status = STATUS_MORE_PROCESSING_REQUIRED;\r
+       goto exit;\r
+\r
+release:       \r
+       IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+exit:  \r
+       BUS_EXIT( BUS_DBG_POWER );\r
+       return status;\r
 }\r
 \r
 \r
+static NTSTATUS __device_power_down_workItem_completion(\r
+       IN                              DEVICE_OBJECT   *p_dev_obj,\r
+       IN                              IRP                             *p_irp,\r
+       IN                              void                            *context )\r
+{\r
+       bus_fdo_ext_t           *p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension;\r
+       UNUSED_PARAM( context );\r
+\r
+       BUS_ENTER( BUS_DBG_POWER );\r
+\r
+       PoStartNextPowerIrp( p_irp );\r
+       IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
+\r
+       BUS_EXIT( BUS_DBG_POWER );\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+/* Work item callback to handle DevicePowerD3 IRPs at passive level. */\r
+static void\r
+__device_power_down_workItem(\r
+       IN                              DEVICE_OBJECT*                          p_dev_obj,\r
+       IN                              void*                                           context )\r
+{\r
+       IO_STACK_LOCATION       *p_io_stack;\r
+       bus_fdo_ext_t           *p_ext;\r
+       IRP                                     *p_irp;\r
+       POWER_STATE                     power_state;\r
+\r
+       BUS_ENTER( BUS_DBG_POWER );\r
+\r
+       p_ext = (bus_fdo_ext_t*)p_dev_obj->DeviceExtension;\r
+       p_irp = (IRP*)context;\r
+       p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
+\r
+       IoFreeWorkItem( p_ext->p_po_work_item );\r
+       p_ext->p_po_work_item = NULL;\r
+\r
+       p_ext->device_power_state = p_io_stack->Parameters.Power.State.DeviceState;\r
+       power_state = PoSetPowerState( p_dev_obj, DevicePowerState,\r
+               p_io_stack->Parameters.Power.State );\r
+\r
+       BUS_PRINT( BUS_DBG_POWER, \r
+               ("PoSetPowerState: old state %d, new state to %d, IRQL %d\n", \r
+               power_state.DeviceState, p_ext->device_power_state, KeGetCurrentIrql() ));\r
+\r
+       CL_PRINT_TO_EVENT_LOG( p_dev_obj, EVENT_IBBUS_ANY_WARN,\r
+               ("Power decreased to: device %d, system %d.\n",\r
+               (int)p_ext->device_power_state, (int)p_ext->system_power_state));\r
+\r
+       BUS_PRINT( BUS_DBG_POWER, \r
+               ("***** deregister CA \n"));\r
+\r
+       __deregister_ca( p_dev_obj );\r
+\r
+       IoCopyCurrentIrpStackLocationToNext( p_irp );\r
+#pragma warning( push, 3 )\r
+       IoSetCompletionRoutine( p_irp, __device_power_down_workItem_completion,\r
+               NULL, TRUE, TRUE, TRUE );\r
+#pragma warning( pop )\r
+       PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
+\r
+       BUS_EXIT( BUS_DBG_POWER );\r
+}\r
+\r
+\r
+\r
 static NTSTATUS\r
 __fdo_set_power(\r
        IN                              DEVICE_OBJECT* const            p_dev_obj,\r
@@ -1289,35 +1480,63 @@ __fdo_set_power(
        p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
 \r
        BUS_TRACE( BUS_DBG_POWER, \r
-               ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d \n",\r
+               ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d, IRQL %d  \n",\r
                p_dev_obj, p_ext,\r
                (p_io_stack->Parameters.Power.Type)\r
                        ? "DevicePowerState" : "SystemPowerState",\r
                p_io_stack->Parameters.Power.State.DeviceState, \r
-               p_io_stack->Parameters.Power.ShutdownType ));\r
+               p_io_stack->Parameters.Power.ShutdownType, KeGetCurrentIrql() ));\r
 \r
        switch( p_io_stack->Parameters.Power.Type )\r
        {\r
        case SystemPowerState:\r
-#if 0\r
-               /*\r
-                * Process on the way up the stack.  We cannot block since the \r
-                * power dispatch function can be called at elevated IRQL if the\r
-                * device is in a paging/hibernation/crash dump path.\r
-                */\r
+               /* Pass down and let the PDO driver handle it. */\r
+               p_ext->system_power_state = p_io_stack->Parameters.Power.State.SystemState;\r
+               *p_action = IrpIgnore;\r
+               status = STATUS_SUCCESS;\r
+               break;\r
+\r
+       case DevicePowerState:\r
                IoMarkIrpPending( p_irp );\r
-               IoCopyCurrentIrpStackLocationToNext( p_irp );\r
+               if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && \r
+                       p_ext->system_power_state == PowerSystemWorking)\r
+               { /* power up */\r
+                       /* If we're already powered up, just pass down. */\r
+                       if( p_ext->device_power_state == PowerDeviceD0 )\r
+                       {\r
+                               status = STATUS_SUCCESS;\r
+                               *p_action = IrpIgnore;\r
+                               break;\r
+                       }\r
+\r
+                       /* Process in I/O completion callback. */\r
+                       IoCopyCurrentIrpStackLocationToNext( p_irp );\r
 #pragma warning( push, 3 )\r
-               IoSetCompletionRoutine( p_irp, __set_power_completion, NULL, \r
-                       TRUE, TRUE, TRUE );\r
+                       IoSetCompletionRoutine( p_irp, __device_power_up_completion, NULL, \r
+                               TRUE, TRUE, TRUE );\r
 #pragma warning( pop )\r
-               PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
+                       PoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
+               }\r
+               else\r
+               { /* power down */\r
+\r
+                       /* Process in a work item - deregister_ca and HcaDeinit block. */\r
+                       ASSERT( !p_ext->p_po_work_item );\r
+                       p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj );\r
+                       if( !p_ext->p_po_work_item )\r
+                       {\r
+                               status = STATUS_INSUFFICIENT_RESOURCES;\r
+                               break;\r
+                       }\r
 \r
+                       /* Process in work item callback. */\r
+                       IoQueueWorkItem(\r
+                               p_ext->p_po_work_item, __device_power_down_workItem, DelayedWorkQueue, p_irp );\r
+               }\r
                *p_action = IrpDoNothing;\r
                status = STATUS_PENDING;\r
                break;\r
-#endif\r
-       case DevicePowerState:\r
+\r
        default:\r
                /* Pass down and let the PDO driver handle it. */\r
                *p_action = IrpIgnore;\r
@@ -1325,6 +1544,9 @@ __fdo_set_power(
                break;\r
        }\r
 \r
+       if( !NT_SUCCESS( status ) )\r
+               *p_action = IrpComplete;\r
+\r
        BUS_EXIT( BUS_DBG_POWER );\r
        return status;\r
 }\r
index a0d083e..3fc5a90 100644 (file)
@@ -2106,7 +2106,9 @@ port_set_power(
 \r
        if ((p_io_stack->Parameters.Power.Type == SystemPowerState) &&\r
                (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate ||\r
-               p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 ))\r
+               p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 ||\r
+               p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping2 ||\r
+               p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping3 ))\r
        {\r
                BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj));\r
                p_ext->b_hibernating = TRUE;\r
index e4f17dc..72c2db2 100644 (file)
@@ -437,7 +437,7 @@ EvtDeviceD0Entry(
 \r
        MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("PreviousState 0x%x\n", PreviousState));\r
 \r
-       // start card (needed after Hibernetion)\r
+       // start card (needed after Hibernation or standby)\r
        if (PreviousState > WdfPowerDeviceD0)\r
                status = __start_card( Device, p_fdo );\r
        if ( !NT_SUCCESS( status ) ) \r
index a8be176..ff4e526 100644 (file)
@@ -76,12 +76,6 @@ static int __get_dev_info(PFDO_DEVICE_DATA p_fdo, __be64 *node_guid, u32 *hw_id)
 \r
 #ifndef USE_WDM_FRAMEWORK\r
 \r
-//\r
-// TODO: add support for Hibernate/Standby as in WDM version below\r
-//\r
-\r
-\r
-\r
 static ci_interface_t*\r
 __alloc_hca_ifc(\r
        IN                              PFDO_DEVICE_DATA const          p_fdo )\r
@@ -197,10 +191,25 @@ EvtDeviceD0Entry(
        IN WDF_POWER_DEVICE_STATE  PreviousState\r
        )\r
 {\r
-       UNUSED_PARAM(Device);\r
-       UNUSED_PARAM(PreviousState);\r
+       NTSTATUS status;\r
+       PFDO_DEVICE_DATA p_fdo = FdoGetData(Device);\r
+\r
        HCA_ENTER( HCA_DBG_PNP );\r
        HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, ("EvtDeviceD0Entry: PreviousState 0x%x\n", PreviousState));\r
+       // start card (needed after Hibernation or standby)\r
+       if (PreviousState > WdfPowerDeviceD0) {\r
+               /* get MLX4_BUS IB interface */\r
+               if ( !p_fdo->bus_ib_ifc_taken ) {\r
+                       status = WdfFdoQueryForInterface( Device, &MLX4_BUS_IB_INTERFACE_GUID,\r
+                               (PINTERFACE)&p_fdo->bus_ib_ifc, sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL );\r
+                       if( !NT_SUCCESS( status ) ) {\r
+                               HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting MLX4 BUS interface failed: status=0x%x\n", status));\r
+                               return status;\r
+                       }\r
+                       p_fdo->bus_ib_ifc_taken = TRUE;\r
+                       p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo;\r
+               }\r
+       }\r
        HCA_EXIT( HCA_DBG_PNP );\r
        return STATUS_SUCCESS;\r
 }\r
@@ -220,6 +229,8 @@ EvtDeviceD0Exit(
 \r
        switch (TargetState) {\r
        case WdfPowerDeviceD1:  /* hopefully, it is STANDBY state */\r
+       case WdfPowerDeviceD2:  /* hopefully, it is STANDBY state */\r
+       case WdfPowerDeviceD3:  /* hopefully, it is STANDBY state */\r
        case WdfPowerDevicePrepareForHibernation:\r
                if (atomic_read(&p_fdo->usecnt)) {\r
                        status = STATUS_UNSUCCESSFUL;\r
@@ -231,6 +242,14 @@ EvtDeviceD0Exit(
                break;\r
        }\r
 \r
+       if (TargetState > WdfPowerDeviceD0) {\r
+               if(p_fdo->bus_ib_ifc_taken) {\r
+                       PINTERFACE p_ifc = (PINTERFACE)&p_fdo->bus_ib_ifc;\r
+                       p_ifc->InterfaceDereference( p_ifc->Context );\r
+                       p_fdo->bus_ib_ifc_taken = FALSE;\r
+               }\r
+       }\r
+\r
        HCA_EXIT( HCA_DBG_PNP );\r
        return status;\r
 }\r
@@ -268,14 +287,16 @@ EvtDevicePrepareHardware(
        p_fdo->bus_pci_ifc_taken = TRUE;\r
        \r
        /* get MLX4_BUS IB interface */\r
-       status = WdfFdoQueryForInterface( Device, &MLX4_BUS_IB_INTERFACE_GUID,\r
-               (PINTERFACE)&p_fdo->bus_ib_ifc, sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL );\r
-       if( !NT_SUCCESS( status ) ) {\r
-               HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting MLX4 BUS interface failed: status=0x%x\n", status));\r
-               return status;\r
+       if ( !p_fdo->bus_ib_ifc_taken ) {\r
+               status = WdfFdoQueryForInterface( Device, &MLX4_BUS_IB_INTERFACE_GUID,\r
+                       (PINTERFACE)&p_fdo->bus_ib_ifc, sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL );\r
+               if( !NT_SUCCESS( status ) ) {\r
+                       HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Getting MLX4 BUS interface failed: status=0x%x\n", status));\r
+                       return status;\r
+               }\r
+               p_fdo->bus_ib_ifc_taken = TRUE;\r
+               p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo;\r
        }\r
-       p_fdo->bus_ib_ifc_taken = TRUE;\r
-       p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo;\r
 \r
        InitializeListHead(&p_fdo->hca.event_list);\r
        KeInitializeSpinLock(&p_fdo->hca.event_list_lock);\r
@@ -1397,6 +1418,8 @@ hca_query_power(
                switch( pIoStack->Parameters.Power.State.SystemState )\r
                {\r
                        case PowerSystemSleeping1:      // STANDBY support\r
+                       case PowerSystemSleeping2:      // STANDBY support\r
+                       case PowerSystemSleeping3:      // STANDBY support\r
                        case PowerSystemHibernate:\r
                        {\r
                                PFDO_DEVICE_DATA p_fdo = (PFDO_DEVICE_DATA)p_dev_obj->DeviceExtension;\r
index b1d810d..d34039d 100644 (file)
@@ -981,6 +981,8 @@ hca_query_power(
                switch( pIoStack->Parameters.Power.State.SystemState )\r
                {\r
                        case PowerSystemSleeping1:      // STANDBY support\r
+                       case PowerSystemSleeping2:      // STANDBY support\r
+                       case PowerSystemSleeping3:      // STANDBY support\r
                        case PowerSystemHibernate:\r
                        {\r
                                hca_dev_ext_t*p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension;\r