[MLX4] added Hibernate/Standby support. (mlnx: 2906)
authorleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Mon, 4 Aug 2008 12:23:51 +0000 (12:23 +0000)
committerleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Mon, 4 Aug 2008 12:23:51 +0000 (12:23 +0000)
Mellanox HCA cards do not have Power Management support so far.
So MLX4 driver resets the card on power-down  and starts its back on power-up.
Pay attention, one can go to Standby/Hibernate only when there is no running IB applications (including WSD).
Otherwise he will get an error window with a message like: "Driver mlx4_hca.sys refuses to go Hibernate/Standby".
MTHCA driver behaves upon Hibernate/Standby the same way.

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

hw/mlx4/kernel/bus/drv/drv.c
hw/mlx4/kernel/bus/drv/drv.h
hw/mlx4/kernel/hca/drv.c

index 5e8c80c..f531a8b 100644 (file)
@@ -101,6 +101,7 @@ EvtInterruptIsr(
 \r
 #endif\r
 \r
+static \r
 NTSTATUS\r
 __create_child(\r
        __in WDFDEVICE  Device,\r
@@ -200,6 +201,7 @@ Routine Description:
        return status;\r
 }\r
 \r
+static \r
 NTSTATUS\r
 __do_static_enumeration(\r
        IN WDFDEVICE Device\r
@@ -223,11 +225,14 @@ Routine Description:
        NTSTATUS status = STATUS_SUCCESS;\r
        int i;\r
        int number_of_ib_ports;\r
-\r
-       // TODO:Need to add an event log in the case of errors\r
+       PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
+       struct mlx4_dev *mdev   = p_fdo->pci_dev.dev;\r
 \r
        MLX4_ENTER(MLX4_DBG_DRV);\r
 \r
+       if ( p_fdo->children_created )\r
+               goto end;\r
+       \r
        // eventually we'll have all information about children in Registry\r
        // DriverEntry will read it into a Global storage and\r
        // this routine will create all the children on base on this info\r
@@ -237,7 +242,7 @@ Routine Description:
        if(number_of_ib_ports > 0) {\r
                status = __create_child(Device, BUS_HARDWARE_IDS, BUS_HARDWARE_DESCRIPTION, 0 );\r
                if (!NT_SUCCESS(status)) {\r
-                        MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (ib)failed with 0x%x\n", status));\r
+                        MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (ib)failed with 0x%x\n", status));\r
                }\r
        }\r
 \r
@@ -246,15 +251,107 @@ Routine Description:
                if(mlx4_is_eth_port(i)) {\r
                        status = __create_child(Device, ETH_HARDWARE_IDS, ETH_HARDWARE_DESCRIPTION, i+1 );\r
                        if (!NT_SUCCESS(status)) {\r
-                                MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (eth) failed with 0x%x\n", status));\r
+                                MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__create_child (eth) failed with 0x%x\n", status));\r
                        }\r
                }\r
        }\r
 \r
+       p_fdo->children_created = TRUE;\r
+       \r
+end:\r
        MLX4_EXIT( MLX4_DBG_DRV );\r
        return status;\r
 }\r
 \r
+static \r
+NTSTATUS\r
+__start_card( \r
+       IN PFDO_DEVICE_DATA p_fdo \r
+       )\r
+{\r
+#ifndef USE_WDM_INTERRUPTS\r
+               int i;\r
+#endif\r
+       int err;\r
+       NTSTATUS status = STATUS_SUCCESS;\r
+       struct pci_dev *pdev = &p_fdo->pci_dev;\r
+\r
+       MLX4_ENTER(MLX4_DBG_DRV);\r
+\r
+       if ( p_fdo->card_started )\r
+               goto err; \r
+               \r
+       // enable the card\r
+       status = pci_hca_enable( &pdev->bus_pci_ifc, &pdev->pci_cfg_space );\r
+       if( !NT_SUCCESS( status ) ) \r
+               goto err;\r
+\r
+       //\r
+       // init the card\r
+       //\r
+\r
+#ifndef USE_WDM_INTERRUPTS\r
+       // enable interrupts for start up\r
+       for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) \r
+               WdfInterruptEnable(p_fdo->interrupt[i].WdfInterrupt);\r
+#endif \r
+\r
+       // NET library\r
+       err = mlx4_init_one( &p_fdo->pci_dev );\r
+       if (err) {\r
+               status = errno_to_ntstatus(err);\r
+               goto err;\r
+       }\r
+\r
+#ifndef USE_WDM_INTERRUPTS\r
+       //\r
+       // complete filling interrupt context (for more efficiency)\r
+       //\r
+       for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {\r
+               struct mlx4_priv *priv = mlx4_priv( p_fdo->pci_dev.dev );\r
+               PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( \r
+                       p_fdo->interrupt[i].WdfInterrupt, INTERRUPT_DATA );\r
+\r
+               p_isr_ctx->eq = &priv->eq_table.eq[i];\r
+       }\r
+#endif\r
+\r
+       //\r
+       // prepare MLX4 IB interface\r
+       //\r
+\r
+       // fill the header\r
+       p_fdo->bus_ib_ifc.i.Size = sizeof(MLX4_BUS_IB_INTERFACE);\r
+       p_fdo->bus_ib_ifc.i.Version = MLX4_BUS_IB_INTERFACE_VERSION;\r
+       // Let the framework handle reference counting.\r
+       p_fdo->bus_ib_ifc.i.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;\r
+       p_fdo->bus_ib_ifc.i.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;\r
+\r
+       p_fdo->bus_ib_ifc.pdev = &p_fdo->pci_dev;\r
+       p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;\r
+       p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev;\r
+       p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);\r
+\r
+       p_fdo->card_started = TRUE;\r
+\r
+err:\r
+       MLX4_EXIT( MLX4_DBG_DRV );\r
+       return status;\r
+}\r
+\r
+static\r
+void\r
+__stop_card(\r
+       IN PFDO_DEVICE_DATA p_fdo\r
+       )\r
+{\r
+       if ( p_fdo->card_started ) {\r
+               p_fdo->card_started = FALSE;\r
+               mlx4_remove_one( &p_fdo->pci_dev );\r
+       }\r
+}\r
+\r
+\r
 NTSTATUS\r
 EvtDeviceD0Entry(\r
        IN WDFDEVICE  Device,\r
@@ -262,37 +359,39 @@ EvtDeviceD0Entry(
        )\r
 {\r
        NTSTATUS status = STATUS_SUCCESS;\r
-       \r
-       UNUSED_PARAM(Device);\r
-       UNUSED_PARAM(PreviousState);\r
+       PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
+       struct pci_dev *pdev    = &p_fdo->pci_dev;\r
+       struct mlx4_dev *mdev;\r
 \r
        MLX4_ENTER(MLX4_DBG_DRV);\r
 \r
        MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("PreviousState 0x%x\n", PreviousState));\r
 \r
+       // start card (needed after Hibernetion)\r
+       if (PreviousState > WdfPowerDeviceD0)\r
+               __start_card( p_fdo );\r
+       mdev = pdev->dev;\r
+\r
+       // create child device\r
        status = __do_static_enumeration(Device);\r
-       if (!NT_SUCCESS(status)) {\r
-                MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__do_static_enumeration failed with 0x%x\n", status));\r
-       }\r
+               if (!NT_SUCCESS(status)) {\r
+                       MLX4_PRINT_EV(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, ("__do_static_enumeration failed with 0x%x\n", status));\r
+                       goto err;\r
+               }\r
 \r
-       {\r
-               PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
-               struct pci_dev *pdev    = &p_fdo->pci_dev;\r
-               struct mlx4_dev *mdev   = pdev->dev;\r
-\r
-               MLX4_PRINT_EV(TRACE_LEVEL_INFORMATION ,MLX4_DBG_DRV ,\r
-                       ("Ven %x Dev %d Fw %d.%d.%d Drv %s (%s), BD %s\n", \r
-                       (unsigned)pdev->ven_id, (unsigned)pdev->dev_id,\r
-                       (int) (mdev->caps.fw_ver >> 32),\r
-                       (int) (mdev->caps.fw_ver >> 16) & 0xffff, \r
-                       (int) (mdev->caps.fw_ver & 0xffff),\r
-                       DRV_VERSION, DRV_RELDATE, \r
-                       mlx4_is_livefish(mdev) ? "Y" : "N"\r
-                       ));\r
-       }\r
+       // Log Success Message\r
+       MLX4_PRINT_EV(TRACE_LEVEL_INFORMATION ,MLX4_DBG_DRV ,\r
+               ("Ven %x Dev %d Fw %d.%d.%d, IsBurnDevice %s\n", \r
+               (unsigned)pdev->ven_id, (unsigned)pdev->dev_id,\r
+               (int) (mdev->caps.fw_ver >> 32),\r
+               (int) (mdev->caps.fw_ver >> 16) & 0xffff, \r
+               (int) (mdev->caps.fw_ver & 0xffff),\r
+               mlx4_is_livefish(mdev) ? "Y" : "N"\r
+               ));\r
 \r
+err:\r
        MLX4_EXIT( MLX4_DBG_DRV );\r
-       return STATUS_SUCCESS;\r
+       return status;\r
 }\r
 \r
 NTSTATUS\r
@@ -301,10 +400,14 @@ EvtDeviceD0Exit(
        IN WDF_POWER_DEVICE_STATE  TargetState\r
        )\r
 {\r
-       UNUSED_PARAM(Device);\r
-       UNUSED_PARAM(TargetState);\r
+       PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
+       \r
        MLX4_ENTER(MLX4_DBG_DRV);\r
        MLX4_PRINT(TRACE_LEVEL_INFORMATION, MLX4_DBG_DRV, ("TargetState 0x%x\n", TargetState));\r
+\r
+       if (TargetState > WdfPowerDeviceD0)\r
+               __stop_card( p_fdo );\r
+\r
        MLX4_EXIT( MLX4_DBG_DRV );\r
        return STATUS_SUCCESS;\r
 }\r
@@ -516,7 +619,6 @@ err:
        return status;\r
 }\r
 \r
-\r
 NTSTATUS\r
 EvtPrepareHardware(\r
        IN WDFDEVICE  Device,\r
@@ -524,13 +626,8 @@ EvtPrepareHardware(
        IN WDFCMRESLIST  ResourcesTranslated\r
        )\r
 {\r
-#ifndef USE_WDM_INTERRUPTS\r
-       int i;\r
-#endif\r
-       int err;\r
        NTSTATUS status;\r
        PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
-       struct pci_dev *pdev = &p_fdo->pci_dev;\r
 \r
        MLX4_ENTER(MLX4_DBG_DRV);\r
 \r
@@ -541,58 +638,8 @@ EvtPrepareHardware(
                goto err;\r
        }\r
 \r
-       // enable the card\r
-       status = pci_hca_enable( &pdev->bus_pci_ifc, &pdev->pci_cfg_space );\r
-       if( !NT_SUCCESS( status ) ) \r
-               goto err;\r
-\r
-       //\r
-       // init the card\r
-       //\r
-\r
-#ifndef USE_WDM_INTERRUPTS\r
-       // enable interrupts for start up\r
-       for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) \r
-               WdfInterruptEnable(p_fdo->interrupt[i].WdfInterrupt);\r
-#endif \r
-\r
-       // NET library\r
-       err = mlx4_init_one( &p_fdo->pci_dev );\r
-       if (err) {\r
-               status = errno_to_ntstatus(err);\r
-               goto err;\r
-       }\r
-\r
-#ifndef USE_WDM_INTERRUPTS\r
-       //\r
-       // complete filling interrupt context (for more efficiency)\r
-       //\r
-       for ( i = 0; i < MLX4_MAX_INTERRUPTS; ++i ) {\r
-               struct mlx4_priv *priv = mlx4_priv( p_fdo->pci_dev.dev );\r
-               PINTERRUPT_DATA p_isr_ctx = WdfObjectGetTypedContext( \r
-                       p_fdo->interrupt[i].WdfInterrupt, INTERRUPT_DATA );\r
-\r
-               p_isr_ctx->eq = &priv->eq_table.eq[i];\r
-       }\r
-#endif\r
-\r
-       //\r
-       // prepare MLX4 IB interface\r
-       //\r
-\r
-       // fill the header\r
-       p_fdo->bus_ib_ifc.i.Size = sizeof(MLX4_BUS_IB_INTERFACE);\r
-       p_fdo->bus_ib_ifc.i.Version = MLX4_BUS_IB_INTERFACE_VERSION;\r
-       // Let the framework handle reference counting.\r
-       p_fdo->bus_ib_ifc.i.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;\r
-       p_fdo->bus_ib_ifc.i.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;\r
-\r
-       p_fdo->bus_ib_ifc.pdev = &p_fdo->pci_dev;\r
-       p_fdo->bus_ib_ifc.p_ibdev = p_fdo->pci_dev.ib_dev;\r
-       p_fdo->bus_ib_ifc.pmlx4_dev = to_mdev(p_fdo->pci_dev.ib_dev)->dev;\r
-       p_fdo->bus_ib_ifc.is_livefish = mlx4_is_livefish(p_fdo->pci_dev.dev);\r
-\r
-       status = STATUS_SUCCESS;\r
+       // start the card\r
+       status = __start_card( p_fdo );\r
        \r
 err:\r
        MLX4_EXIT( MLX4_DBG_DRV );\r
@@ -611,7 +658,7 @@ EvtReleaseHardware(
 \r
        MLX4_ENTER(MLX4_DBG_DRV);\r
 \r
-       mlx4_remove_one( &p_fdo->pci_dev );\r
+       __stop_card( p_fdo );\r
        __put_resources( p_fdo );\r
 \r
        MLX4_EXIT( MLX4_DBG_DRV );\r
index 1803780..636f7e1 100644 (file)
@@ -62,11 +62,13 @@ typedef struct _FDO_DEVICE_DATA
        WDFWAITLOCK                                     ChildLock;\r
        WDFDEVICE                                       FdoDevice;\r
        struct pci_dev                          pci_dev;\r
+       int                                                     card_started;\r
        int                                                     pci_bus_ifc_taken;\r
        WDFDMAENABLER                           dma_enabler;\r
        int                                                     dma_adapter_taken;\r
        res_interrupt_t                         interrupt[MLX4_MAX_INTERRUPTS];\r
        MLX4_BUS_IB_INTERFACE           bus_ib_ifc;\r
+       int                                                     children_created;\r
        // Data for the Ethernet device\r
 #ifdef _WIN64   \r
     UCHAR   pad[0x8];\r
index fb1209b..c7d66bb 100644 (file)
@@ -88,6 +88,10 @@ 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
 #ifdef ALLOC_PRAGMA\r
 #pragma alloc_text (INIT, DriverEntry)\r
 #pragma alloc_text (PAGE, EvtDeviceAdd)\r
@@ -1616,12 +1620,13 @@ __unmap_hca_memory(
 \r
        HCA_ENTER( HCA_DBG_PNP );\r
 \r
-       for( i = 0; i < HCA_BAR_TYPE_MAX; i++ ) {\r
-               if (pdev->bar[i].virt) {\r
-                       MmUnmapIoSpace( pdev->bar[i].virt, pdev->bar[i].size );\r
-                       cl_memclr( &pdev->bar[i], sizeof(hca_bar_t) );\r
+       if ( pdev )\r
+               for( i = 0; i < HCA_BAR_TYPE_MAX; i++ ) {\r
+                       if (pdev->bar[i].virt) {\r
+                               MmUnmapIoSpace( pdev->bar[i].virt, pdev->bar[i].size );\r
+                               cl_memclr( &pdev->bar[i], sizeof(hca_bar_t) );\r
+                       }\r
                }\r
-       }\r
 \r
        HCA_EXIT( HCA_DBG_PNP );\r
 }\r
@@ -2231,6 +2236,7 @@ __DevicePowerUpCompletionWorkItem(
        IN                              DEVICE_OBJECT*                          p_dev_obj,\r
        IN                              void*                                           context )\r
 {\r
+       int                                     err;\r
        NTSTATUS                        status;\r
        IO_STACK_LOCATION       *pIoStack;\r
        PFDO_DEVICE_DATA        p_fdo;\r
@@ -2250,6 +2256,25 @@ __DevicePowerUpCompletionWorkItem(
        HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, \r
                ("***** Restart the HCA, IRQL %d\n", KeGetCurrentIrql()));\r
 \r
+       /* get MLX4_BUS IB interface */\r
+       status = __get_ifc( p_dev_obj, &MLX4_BUS_IB_INTERFACE_GUID,\r
+               sizeof(MLX4_BUS_IB_INTERFACE), MLX4_BUS_IB_INTERFACE_VERSION, NULL, (PINTERFACE)&p_fdo->bus_ib_ifc);\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
+               goto err_hca_reg;\r
+       }\r
+       p_fdo->bus_ib_ifc_taken = TRUE;\r
+       p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo;\r
+\r
+       /* get node GUID */\r
+       err = __get_dev_info( p_fdo, &p_fdo->hca.guid, &p_fdo->hca.hw_ver );\r
+       if (err) {\r\r
+               HCA_PRINT(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,\r
+                       ("can't get guid - ib_query_device() failed (%08X)\n", err ));\r
+               //TODO: no cleanup on error\r
+               goto err_hca_reg;\r
+       }\r
+\r
        if( p_fdo->p_al_dev ) {\r
                status = __hca_register( p_dev_obj );\r
                if( !NT_SUCCESS( status ) ) {\r
@@ -2384,6 +2409,12 @@ __DevicePowerDownWorkItem(
 \r
        {\r
                __hca_deregister( p_fdo );\r
+\r
+               // release MLX4_BUS resources\r
+               if(p_fdo->bus_ib_ifc_taken) {\r
+                       p_fdo->bus_ib_ifc_taken = FALSE;\r
+                       __put_ifc( (PINTERFACE)&p_fdo->bus_ib_ifc );\r
+               }\r
        }\r
 \r
        IoCopyCurrentIrpStackLocationToNext( p_irp );\r