From: sleybo Date: Wed, 7 Feb 2007 14:29:16 +0000 (+0000) Subject: [MTHCA/IBBUS] add HIBERNATE and STANDBY support (for mthca/bus/ipoib) X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=707a086db7cd71bb19f2c74fa4d596429c97b302;p=~shefty%2Frdma-win.git [MTHCA/IBBUS] add HIBERNATE and STANDBY support (for mthca/bus/ipoib) git-svn-id: svn://openib.tc.cornell.edu/gen1@591 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- diff --git a/trunk/core/al/kernel/al_pnp.c b/trunk/core/al/kernel/al_pnp.c index 5dd72c7b..df7dffa5 100644 --- a/trunk/core/al/kernel/al_pnp.c +++ b/trunk/core/al/kernel/al_pnp.c @@ -479,6 +479,10 @@ __pnp_notify_user( CL_ASSERT( p_context ); CL_ASSERT( p_event_rec ); + AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP, + ("p_event_rec->pnp_event = 0x%x (%s)\n", + p_event_rec->pnp_event, ib_get_pnp_event_str( p_event_rec->pnp_event )) ); + /* Setup the PnP record for the callback. */ cl_memclr( &u, sizeof(u) ); u.user_rec.h_pnp = p_reg; diff --git a/trunk/core/bus/kernel/bus_driver.h b/trunk/core/bus/kernel/bus_driver.h index eb3c3aca..98c00bee 100644 --- a/trunk/core/bus/kernel/bus_driver.h +++ b/trunk/core/bus/kernel/bus_driver.h @@ -172,6 +172,12 @@ typedef struct _bus_pdo_ext */ boolean_t b_reported_missing; + /* Flag to control the behaviour of the driver during hibernation */ + uint32_t b_hibernating; + + /* work item for handling Power Management request */ + PIO_WORKITEM p_po_work_item; + } bus_pdo_ext_t; diff --git a/trunk/core/bus/kernel/bus_iou_mgr.c b/trunk/core/bus/kernel/bus_iou_mgr.c index b3dea68d..6e21b90f 100644 --- a/trunk/core/bus/kernel/bus_iou_mgr.c +++ b/trunk/core/bus/kernel/bus_iou_mgr.c @@ -391,6 +391,8 @@ free_iou_mgr( { CL_ASSERT( !p_ext->b_present ); p_ext->b_reported_missing = TRUE; + BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n", + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->b_present, p_ext->b_reported_missing ) ); continue; } if( p_ext->h_ca ) @@ -492,6 +494,80 @@ iou_mgr_get_bus_relations( } +static ib_api_status_t +__iou_was_hibernated( + IN ib_pnp_iou_rec_t* p_pnp_rec ) +{ + NTSTATUS status; + cl_list_item_t *p_list_item; + bus_iou_ext_t *p_iou_ext; + bus_pdo_ext_t *p_pdo_ext = NULL; + size_t n_devs = 0; + cl_qlist_t* p_pdo_list = &gp_iou_mgr->iou_list; + + BUS_ENTER( BUS_DBG_PNP ); + + cl_mutex_acquire( &gp_iou_mgr->pdo_mutex ); + + /* Count the number of child devices. */ + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + p_iou_ext = (bus_iou_ext_t*)p_pdo_ext; + + /* TODO: maybe we need more search patterns like vend_id, dev_id ... */ + if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating && + (p_iou_ext->guid == p_pnp_rec->pnp_rec.guid) ) + { + n_devs++; + break; + } + + BUS_TRACE( BUS_DBG_PNP, + ("Skipped PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n", + p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, + p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, + p_pdo_ext->b_hibernating, p_iou_ext->guid ) ); + } + + if (n_devs) + { + /* Take a reference on the parent HCA. */ + p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->ca_guid ); + if( !p_pdo_ext->h_ca ) + { + BUS_TRACE( BUS_DBG_ERROR, ("acquire_ca failed to find CA by guid %I64x\n", + p_pnp_rec->ca_guid ) ); + status = IB_INVALID_GUID; + } + else + { + p_pdo_ext->b_hibernating = FALSE; + p_pnp_rec->pnp_rec.context = p_pdo_ext; + status = IB_SUCCESS; + p_iou_ext = (bus_iou_ext_t*)p_pdo_ext; + BUS_TRACE( BUS_DBG_PNP, + ("Found PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n", + p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, + p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, + p_pdo_ext->b_hibernating, p_iou_ext->guid ) ); + } + } + else + { + BUS_TRACE( BUS_DBG_PNP, ("Failed to find PDO for guid %I64x .\n", + p_pnp_rec->pnp_rec.guid ) ); + status = IB_NOT_FOUND; + } + + cl_mutex_release( &gp_iou_mgr->pdo_mutex ); + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} + ib_api_status_t iou_mgr_iou_add( IN ib_pnp_iou_rec_t* p_pnp_rec ) @@ -502,6 +578,16 @@ iou_mgr_iou_add( BUS_ENTER( BUS_DBG_PNP ); + /* Upon hibernating of the computer IB_BUS driver doesn't remove PDO, but + marks with a flag. So we first try to find an existing PDO for this port, + marked with this flag. If it was found, we turn off the flag and use this PDO */ + status = __iou_was_hibernated(p_pnp_rec); + if( status != IB_NOT_FOUND ) + { + BUS_EXIT( BUS_DBG_PNP ); + return status; + } + /* Create the PDO for the new port device. */ status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_iou_ext_t), NULL, FILE_DEVICE_CONTROLLER, @@ -526,6 +612,8 @@ iou_mgr_iou_add( p_iou_ext->pdo.p_parent_ext = bus_globals.p_bus_ext; p_iou_ext->pdo.b_present = TRUE; p_iou_ext->pdo.b_reported_missing = FALSE; + BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n", + p_iou_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_iou_ext, p_iou_ext->pdo.b_present, p_iou_ext->pdo.b_reported_missing ) ); p_iou_ext->guid = p_pnp_rec->pnp_rec.guid; p_iou_ext->vend_id = cl_ntoh32( p_pnp_rec->vend_id ); @@ -594,7 +682,19 @@ iou_mgr_iou_remove( * to proceed should it occur before the port's PDO is cleaned up. */ cl_mutex_acquire( &gp_iou_mgr->pdo_mutex ); + CL_ASSERT( p_ext->h_ca ); + + if( p_ext->b_hibernating ) + { + BUS_TRACE( BUS_DBG_PNP, ("Skip port removing for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d .\n", + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, + p_ext->b_reported_missing, p_ext->b_hibernating ) ); + goto hca_deref; + } + p_ext->b_present = FALSE; + BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n", + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->b_present, p_ext->b_reported_missing ) ); /* Invalidate removal relations for the bus driver. */ IoInvalidateDeviceRelations( bus_globals.p_bus_ext->cl_ext.p_pdo, @@ -604,6 +704,7 @@ iou_mgr_iou_remove( IoInvalidateDeviceRelations( p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations ); +hca_deref: deref_al_obj( &p_ext->h_ca->obj ); p_ext->h_ca = NULL; cl_mutex_release( &gp_iou_mgr->pdo_mutex ); @@ -758,6 +859,8 @@ iou_surprise_remove( p_ext = p_dev_obj->DeviceExtension; p_ext->pdo.b_present = FALSE; p_ext->pdo.b_reported_missing = TRUE; + BUS_TRACE( BUS_DBG_PNP, ("%s: ext %p, present %d, missing %d .\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) ); *p_action = IrpComplete; @@ -1280,6 +1383,47 @@ iou_query_interface( } + +/* Work item callback to handle DevicePowerD3 IRPs at passive level. */ +static void +__HibernateUpWorkItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + IO_STACK_LOCATION *p_io_stack; + bus_pdo_ext_t *p_ext; + IRP *p_irp; + POWER_STATE powerState; + + BUS_ENTER( BUS_DBG_POWER ); + + p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension; + p_irp = (IRP*)context; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + IoFreeWorkItem( p_ext->p_po_work_item ); + p_ext->p_po_work_item = NULL; + + while (!p_ext->h_ca) { + BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n")); + cl_thread_suspend( 200 ); /* suspend for 200 ms */ + } + + p_ext->dev_po_state = p_io_stack->Parameters.Power.State; + powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); + + BUS_TRACE( BUS_DBG_POWER, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_ext->dev_po_state )); + + p_irp->IoStatus.Status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + + BUS_EXIT( BUS_DBG_POWER ); +} + /* * The PDOs created by the IB Bus driver are software devices. As such, * all power states are supported. It is left to the HCA power policy @@ -1291,6 +1435,7 @@ iou_set_power( IN IRP* const p_irp, OUT cl_irp_action_t* const p_action ) { + NTSTATUS status = STATUS_SUCCESS; IO_STACK_LOCATION *p_io_stack; bus_pdo_ext_t *p_ext; @@ -1299,8 +1444,42 @@ iou_set_power( p_ext = p_dev_obj->DeviceExtension; p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + BUS_TRACE( BUS_DBG_POWER, + ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n", + p_dev_obj, p_ext, + (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + p_io_stack->Parameters.Power.State.DeviceState, + p_io_stack->Parameters.Power.ShutdownType )); + + if ((p_io_stack->Parameters.Power.Type == SystemPowerState) && + (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate || + p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 )) + { + BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj)); + p_ext->b_hibernating = TRUE; + } + if( p_io_stack->Parameters.Power.Type == DevicePowerState ) { + /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */ + if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating) + { + /* Process in a work item - deregister_ca and HcaDeinit block. */ + ASSERT( !p_ext->p_po_work_item ); + p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj ); + if( !p_ext->p_po_work_item ) + status = STATUS_INSUFFICIENT_RESOURCES; + else { + /* Process in work item callback. */ + IoMarkIrpPending( p_irp ); + IoQueueWorkItem( + p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp ); + *p_action = IrpDoNothing; + BUS_EXIT( BUS_DBG_POWER ); + return STATUS_PENDING; + } + } + /* Notify the power manager. */ p_ext->dev_po_state = p_io_stack->Parameters.Power.State; PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); diff --git a/trunk/core/bus/kernel/bus_pnp.c b/trunk/core/bus/kernel/bus_pnp.c index 089f77c6..00190ff4 100644 --- a/trunk/core/bus/kernel/bus_pnp.c +++ b/trunk/core/bus/kernel/bus_pnp.c @@ -827,12 +827,13 @@ __fdo_query_power( /* Fail any requests to hibernate or sleep the system. */ switch( p_io_stack->Parameters.Power.State.SystemState ) { + case PowerSystemHibernate: + case PowerSystemSleeping1: // STANDBY support case PowerSystemWorking: case PowerSystemShutdown: - /* We only support fully working and shutdown system states. */ - break; + break; - default: + default: status = STATUS_NOT_SUPPORTED; } break; @@ -931,7 +932,7 @@ __set_power_completion( status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state, __request_power_completion, p_irp, NULL ); - if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) + if( status != STATUS_PENDING ) { PoStartNextPowerIrp( p_irp ); /* Propagate the failure. */ @@ -962,6 +963,13 @@ __fdo_set_power( p_ext = p_dev_obj->DeviceExtension; p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + BUS_TRACE( BUS_DBG_POWER, + ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d \n", + p_dev_obj, p_ext, + (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + p_io_stack->Parameters.Power.State.DeviceState, + p_io_stack->Parameters.Power.ShutdownType )); + switch( p_io_stack->Parameters.Power.Type ) { case SystemPowerState: @@ -1034,6 +1042,8 @@ bus_get_relations( return STATUS_NO_SUCH_DEVICE; } + BUS_TRACE( BUS_DBG_PNP, ("Found %d PDOs .\n", n_devs )); + /* Add space for our child IOUs. */ status = cl_alloc_relations( p_irp, n_devs ); if( !NT_SUCCESS( status ) ) @@ -1058,12 +1068,18 @@ bus_get_relations( * the PDO will get cleaned up. */ p_pdo_ext->b_reported_missing = TRUE; + BUS_TRACE( BUS_DBG_PNP, ("Don't report PDO! %s: PDO %p, ext %p, present %d, missing %d .\n", + p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, + p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing ) ); continue; } if( ca_guid && p_pdo_ext->ca_guid != ca_guid ) continue; + BUS_TRACE( BUS_DBG_PNP, ("Reported PDO %p(=%p), ext %p.\n", + p_pdo_ext->cl_ext.p_self_do, p_pdo_ext->cl_ext.p_pdo, p_pdo_ext )); + p_rel->Objects[p_rel->Count] = p_pdo_ext->cl_ext.p_pdo; ObReferenceObject( p_rel->Objects[p_rel->Count++] ); } diff --git a/trunk/core/bus/kernel/bus_port_mgr.c b/trunk/core/bus/kernel/bus_port_mgr.c index b7024794..60b4f7b4 100644 --- a/trunk/core/bus/kernel/bus_port_mgr.c +++ b/trunk/core/bus/kernel/bus_port_mgr.c @@ -385,6 +385,8 @@ free_port_mgr( { CL_ASSERT( !p_ext->b_present ); p_ext->b_reported_missing = TRUE; + BUS_TRACE( BUS_DBG_PNP, ("%s: PDO %p, ext %p, present %d, missing %d .\n", + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, p_ext->b_reported_missing ) ); continue; } if( p_ext->h_ca ) @@ -396,6 +398,8 @@ free_port_mgr( /* Release the reference on the CA object. */ deref_al_obj( &p_ext->h_ca->obj ); } + BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s: PDO %p, ext %p\n", + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext ) ); IoDeleteDevice( p_ext->cl_ext.p_self_do ); } @@ -485,6 +489,78 @@ port_mgr_get_bus_relations( return STATUS_SUCCESS; } +static ib_api_status_t +__port_was_hibernated( + IN ib_pnp_port_rec_t* p_pnp_rec ) +{ + NTSTATUS status; + cl_list_item_t *p_list_item; + bus_port_ext_t *p_port_ext; + bus_pdo_ext_t *p_pdo_ext = NULL; + size_t n_devs = 0; + cl_qlist_t* p_pdo_list = &gp_port_mgr->port_list; + + BUS_ENTER( BUS_DBG_PNP ); + + cl_mutex_acquire( &gp_port_mgr->pdo_mutex ); + + /* Count the number of child devices. */ + for( p_list_item = cl_qlist_head( p_pdo_list ); + p_list_item != cl_qlist_end( p_pdo_list ); + p_list_item = cl_qlist_next( p_list_item ) ) + { + p_pdo_ext = PARENT_STRUCT( p_list_item, bus_pdo_ext_t, list_item ); + p_port_ext = (bus_port_ext_t*)p_pdo_ext; + + if( p_pdo_ext->b_present && p_pdo_ext->b_hibernating && + (p_port_ext->port_guid == p_pnp_rec->p_port_attr->port_guid) ) + { + n_devs++; + break; + } + + BUS_TRACE( BUS_DBG_PNP, + ("Skipped PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n", + p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, + p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, + p_pdo_ext->b_hibernating, p_port_ext->port_guid ) ); + } + + if (n_devs) + { + /* Take a reference on the parent HCA. */ + p_pdo_ext->h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid ); + if( !p_pdo_ext->h_ca ) + { + BUS_TRACE( BUS_DBG_ERROR, ("acquire_ca failed to find CA by guid %I64x\n", + p_pnp_rec->p_ca_attr->ca_guid ) ); + status = IB_INVALID_GUID; + } + else + { + p_pdo_ext->b_hibernating = FALSE; + p_pnp_rec->pnp_rec.context = p_pdo_ext; + status = IB_SUCCESS; + p_port_ext = (bus_port_ext_t*)p_pdo_ext; + BUS_TRACE( BUS_DBG_PNP, + ("Found PDO for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d, port_guid %I64x.\n", + p_pdo_ext->cl_ext.vfptr_pnp_po->identity, p_pdo_ext->cl_ext.p_self_do, + p_pdo_ext, p_pdo_ext->b_present, p_pdo_ext->b_reported_missing, + p_pdo_ext->b_hibernating, p_port_ext->port_guid ) ); + } + } + else + { + BUS_TRACE( BUS_DBG_PNP, ("Failed to find PDO for guid %I64x .\n", + p_pnp_rec->p_ca_attr->ca_guid ) ); + status = IB_NOT_FOUND; + } + + cl_mutex_release( &gp_port_mgr->pdo_mutex ); + + BUS_EXIT( BUS_DBG_PNP ); + return status; +} ib_api_status_t port_mgr_port_add( @@ -502,6 +578,16 @@ port_mgr_port_add( return IB_NOT_DONE; } + /* Upon hibernating of the computer IB_BUS driver doesn't remove PDO, but + marks with a flag. So we first try to find an existing PDO for this port, + marked with this flag. If it was found, we turn off the flag and use this PDO */ + status = __port_was_hibernated(p_pnp_rec); + if( status != IB_NOT_FOUND ) + { + BUS_EXIT( BUS_DBG_PNP ); + return status; + } + /* Create the PDO for the new port device. */ status = IoCreateDevice( bus_globals.p_driver_obj, sizeof(bus_port_ext_t), NULL, FILE_DEVICE_CONTROLLER, @@ -526,6 +612,11 @@ port_mgr_port_add( p_port_ext->pdo.p_parent_ext = bus_globals.p_bus_ext; p_port_ext->pdo.b_present = TRUE; p_port_ext->pdo.b_reported_missing = FALSE; + p_port_ext->pdo.b_hibernating = FALSE; + p_port_ext->pdo.p_po_work_item = NULL; + BUS_TRACE( BUS_DBG_PNP, ("Created device for %s: PDO %p,ext %p, present %d, missing %d .\n", + p_port_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_pdo, p_port_ext, p_port_ext->pdo.b_present, + p_port_ext->pdo.b_reported_missing ) ); /* Cache the CA GUID. */ p_port_ext->pdo.ca_guid = p_pnp_rec->p_ca_attr->ca_guid; @@ -534,6 +625,7 @@ port_mgr_port_add( p_port_ext->pdo.h_ca = acquire_ca( p_pnp_rec->p_ca_attr->ca_guid ); if( !p_port_ext->pdo.h_ca ) { + BUS_TRACE( BUS_DBG_PNP, ("Deleted device: PDO %p\n", p_pdo )); IoDeleteDevice( p_pdo ); BUS_TRACE_EXIT( BUS_DBG_ERROR, ("acquire_ca failed to find CA.\n") ); return IB_INVALID_GUID; @@ -586,7 +678,18 @@ port_mgr_port_remove( */ cl_mutex_acquire( &gp_port_mgr->pdo_mutex ); CL_ASSERT( p_ext->h_ca ); + + if( p_ext->b_hibernating ) + { + BUS_TRACE( BUS_DBG_PNP, ("Skip port removing for %s: PDO %p, ext %p, present %d, missing %d, hibernating %d .\n", + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, + p_ext->b_reported_missing, p_ext->b_hibernating ) ); + goto hca_deref; + } + p_ext->b_present = FALSE; + BUS_TRACE( BUS_DBG_PNP, ("Mark removing %s: PDO %p, ext %p, present %d, missing %d .\n", + p_ext->cl_ext.vfptr_pnp_po->identity, p_ext->cl_ext.p_self_do, p_ext, p_ext->b_present, p_ext->b_reported_missing ) ); /* Invalidate removal relations for the bus driver. */ IoInvalidateDeviceRelations( bus_globals.p_bus_ext->cl_ext.p_pdo, @@ -596,6 +699,7 @@ port_mgr_port_remove( IoInvalidateDeviceRelations( p_ext->h_ca->obj.p_ci_ca->verbs.p_hca_dev, BusRelations ); +hca_deref: deref_al_obj( &p_ext->h_ca->obj ); p_ext->h_ca = NULL; cl_mutex_release( &gp_port_mgr->pdo_mutex ); @@ -620,7 +724,6 @@ port_start( /* Notify the Power Manager that the device is started. */ PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); - *p_action = IrpComplete; BUS_EXIT( BUS_DBG_PNP ); return STATUS_SUCCESS; @@ -674,7 +777,7 @@ port_release_resources( /* Remove this PDO from its list. */ cl_mutex_acquire( &gp_port_mgr->pdo_mutex ); - BUS_TRACE( BUS_DBG_PNP, ("Removing port from vector.\n") ); + BUS_TRACE( BUS_DBG_PNP, ("Removing port from vector: PDO %p, ext %p\n", p_dev_obj, p_ext) ); cl_qlist_remove_item( &gp_port_mgr->port_list, &p_ext->pdo.list_item ); cl_mutex_release( &gp_port_mgr->pdo_mutex ); po_state.DeviceState = PowerDeviceD3; @@ -704,7 +807,7 @@ port_remove( cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted ); /* Don't delete the device. It may simply be disabled. */ *p_action = IrpComplete; - BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device still present.\n") ); + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device still present: PDO %p, ext %p\n", p_dev_obj, p_ext) ); return STATUS_SUCCESS; } @@ -713,7 +816,7 @@ port_remove( /* Reset the state to RemovePending. Complib set it to Deleted. */ cl_rollback_pnp_state( &p_ext->pdo.cl_ext ); *p_action = IrpComplete; - BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device not reported missing yet.\n") ); + BUS_TRACE_EXIT( BUS_DBG_PNP, ("Device not reported missing yet: PDO %p, ext %p\n", p_dev_obj, p_ext) ); return STATUS_SUCCESS; } @@ -727,6 +830,8 @@ port_remove( p_irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + BUS_TRACE( BUS_DBG_PNP, ("Deleted device %s: PDO %p(=%p), ext %p\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, p_dev_obj, p_ext ) ); IoDeleteDevice( p_dev_obj ); *p_action = IrpDoNothing; @@ -750,6 +855,9 @@ port_surprise_remove( p_ext = p_dev_obj->DeviceExtension; p_ext->pdo.b_present = FALSE; p_ext->pdo.b_reported_missing = TRUE; + BUS_TRACE( BUS_DBG_PNP, ("%s: PDO %p, ext %p, present %d, missing %d .\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, + p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) ); *p_action = IrpComplete; @@ -1122,6 +1230,7 @@ port_query_ipoib_ifc( ipoib_ifc_data_t *p_ipoib_data; bus_port_ext_t *p_ext; const GUID *p_guid; + BUS_ENTER( BUS_DBG_PNP ); @@ -1129,6 +1238,10 @@ port_query_ipoib_ifc( p_ext = p_dev_obj->DeviceExtension; + BUS_TRACE( BUS_DBG_PNP, ("Query i/f for %s: PDO %p (=%p),ext %p, present %d, missing %d .\n", + p_ext->pdo.cl_ext.vfptr_pnp_po->identity, p_ext->pdo.cl_ext.p_self_do, + p_dev_obj, p_ext, p_ext->pdo.b_present, p_ext->pdo.b_reported_missing ) ); + /* Get the interface. */ status = cl_fwd_query_ifc( p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack ); @@ -1239,6 +1352,47 @@ port_query_interface( } +/* Work item callback to handle DevicePowerD3 IRPs at passive level. */ +static void +__HibernateUpWorkItem( + IN DEVICE_OBJECT* p_dev_obj, + IN void* context ) +{ + IO_STACK_LOCATION *p_io_stack; + bus_pdo_ext_t *p_ext; + IRP *p_irp; + POWER_STATE powerState; + + BUS_ENTER( BUS_DBG_POWER ); + + p_ext = (bus_pdo_ext_t*)p_dev_obj->DeviceExtension; + p_irp = (IRP*)context; + p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + + IoFreeWorkItem( p_ext->p_po_work_item ); + p_ext->p_po_work_item = NULL; + + while (!p_ext->h_ca) { + BUS_TRACE( BUS_DBG_PNP, ("Waiting for the end of HCA registration ... \n")); + cl_thread_suspend( 200 ); /* suspend for 200 ms */ + } + + p_ext->dev_po_state = p_io_stack->Parameters.Power.State; + powerState = PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); + + BUS_TRACE( BUS_DBG_POWER, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_ext->dev_po_state )); + + p_irp->IoStatus.Status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + IoCompleteRequest( p_irp, IO_NO_INCREMENT ); + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + + BUS_EXIT( BUS_DBG_POWER ); +} + + /* * The PDOs created by the IB Bus driver are software devices. As such, * all power states are supported. It is left to the HCA power policy @@ -1250,6 +1404,7 @@ port_set_power( IN IRP* const p_irp, OUT cl_irp_action_t* const p_action ) { + NTSTATUS status = STATUS_SUCCESS; IO_STACK_LOCATION *p_io_stack; bus_pdo_ext_t *p_ext; @@ -1258,8 +1413,42 @@ port_set_power( p_ext = p_dev_obj->DeviceExtension; p_io_stack = IoGetCurrentIrpStackLocation( p_irp ); + BUS_TRACE( BUS_DBG_POWER, + ("SET_POWER for PDO %p (ext %p): type %s, state %d, action %d \n", + p_dev_obj, p_ext, + (p_io_stack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + p_io_stack->Parameters.Power.State.DeviceState, + p_io_stack->Parameters.Power.ShutdownType )); + + if ((p_io_stack->Parameters.Power.Type == SystemPowerState) && + (p_io_stack->Parameters.Power.State.SystemState ==PowerSystemHibernate || + p_io_stack->Parameters.Power.State.SystemState ==PowerSystemSleeping1 )) + { + BUS_TRACE( BUS_DBG_POWER, ("Setting b_hibernating flag for PDO %p \n", p_dev_obj)); + p_ext->b_hibernating = TRUE; + } + if( p_io_stack->Parameters.Power.Type == DevicePowerState ) { + /* after hibernation PDO is not ready for work. we need to wait for finishing of the HCA registration */ + if( p_io_stack->Parameters.Power.State.DeviceState == PowerDeviceD0 && p_ext->b_hibernating) + { + /* Process in a work item - deregister_ca and HcaDeinit block. */ + ASSERT( !p_ext->p_po_work_item ); + p_ext->p_po_work_item = IoAllocateWorkItem( p_dev_obj ); + if( !p_ext->p_po_work_item ) + status = STATUS_INSUFFICIENT_RESOURCES; + else { + /* Process in work item callback. */ + IoMarkIrpPending( p_irp ); + IoQueueWorkItem( + p_ext->p_po_work_item, __HibernateUpWorkItem, DelayedWorkQueue, p_irp ); + *p_action = IrpDoNothing; + BUS_EXIT( BUS_DBG_POWER ); + return STATUS_PENDING; + } + } + /* Notify the power manager. */ p_ext->dev_po_state = p_io_stack->Parameters.Power.State; PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state ); @@ -1267,5 +1456,5 @@ port_set_power( *p_action = IrpComplete; BUS_EXIT( BUS_DBG_POWER ); - return STATUS_SUCCESS; + return status; } diff --git a/trunk/core/complib/kernel/cl_pnp_po.c b/trunk/core/complib/kernel/cl_pnp_po.c index c48169ed..74098023 100644 --- a/trunk/core/complib/kernel/cl_pnp_po.c +++ b/trunk/core/complib/kernel/cl_pnp_po.c @@ -203,6 +203,9 @@ cl_pnp( CL_ENTER( CL_DBG_PNP, p_ext->dbg_lvl ); + CL_TRACE( CL_DBG_PNP, p_ext->dbg_lvl, + ("PDO %p, ext %p\n", p_dev_obj, p_ext) ); + CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); status = IoAcquireRemoveLock( &p_ext->remove_lock, p_irp ); diff --git a/trunk/hw/mthca/kernel/hca_driver.h b/trunk/hw/mthca/kernel/hca_driver.h index 6221696b..4e8fc3b6 100644 --- a/trunk/hw/mthca/kernel/hca_driver.h +++ b/trunk/hw/mthca/kernel/hca_driver.h @@ -124,8 +124,9 @@ typedef struct _hca_dev_ext * ------------------------------------------------ */ /* Cache of the system to device power states. */ DEVICE_POWER_STATE DevicePower[PowerSystemMaximum]; - DEVICE_POWER_STATE PowerState; /* state for Power Manager */ - PIO_WORKITEM pPoWorkItem; + DEVICE_POWER_STATE DevicePowerState; + SYSTEM_POWER_STATE SystemPowerState; + PIO_WORKITEM pPoWorkItem; /* ------------------------------------------------- * IB_AL DATA diff --git a/trunk/hw/mthca/kernel/hca_pnp.c b/trunk/hw/mthca/kernel/hca_pnp.c index f6753cba..4d9bf574 100644 --- a/trunk/hw/mthca/kernel/hca_pnp.c +++ b/trunk/hw/mthca/kernel/hca_pnp.c @@ -467,6 +467,8 @@ __hca_deregister( /* Release AL's CI interface. */ p_ext->ci_ifc.wdm.InterfaceDereference( p_ext->ci_ifc.wdm.Context ); p_ext->state = HCA_STARTED; + HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP, + ("***** HCA deregistered \n")); } } @@ -493,17 +495,18 @@ __hca_register( status = __get_ci_interface( p_dev_obj ); if( !NT_SUCCESS( status ) ) { - HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_SHIM, + HCA_PRINT( TRACE_LEVEL_ERROR,HCA_DBG_PNP, ("__get_ci_interface returned %08x.\n", status)); - return status; + goto exit; } /* Allocate and populate our HCA interface structure. */ p_hca_ifc = __alloc_hca_ifc( p_ext ); if( !p_hca_ifc ) { - HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("__alloc_hca_ifc failed.\n")); - return STATUS_NO_MEMORY; + HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_PNP ,("__alloc_hca_ifc failed.\n")); + status = STATUS_NO_MEMORY; + goto exit; } /* Notify AL that we're available... */ @@ -512,11 +515,16 @@ __hca_register( if( ib_status != IB_SUCCESS ) { p_ext->ci_ifc.wdm.InterfaceDereference( p_ext->ci_ifc.wdm.Context ); - return STATUS_INSUFFICIENT_RESOURCES; + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit; } p_ext->state = HCA_REGISTERED; - return STATUS_SUCCESS; + HCA_PRINT( TRACE_LEVEL_INFORMATION ,HCA_DBG_PNP, + ("***** HCA registered \n")); +exit: + HCA_EXIT( HCA_DBG_PNP ); + return status; } @@ -783,7 +791,7 @@ hca_start( if( !NT_SUCCESS( status ) ) { HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, - ("Lower drivers failed IRP_MN_START_DEVICE.\n")); + ("Lower drivers failed IRP_MN_START_DEVICE (%#x).\n", status)); return status; } @@ -883,9 +891,13 @@ hca_start( } /* We get started fully powered. */ - p_ext->PowerState = PowerDeviceD0; + p_ext->DevicePowerState = PowerDeviceD0; powerState.DeviceState = PowerDeviceD0; - PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState ); + powerState = PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState ); + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_ext->DevicePowerState )); + { struct mthca_dev *mdev = p_ext->hca.mdev; @@ -978,7 +990,7 @@ hca_release_resources( IN DEVICE_OBJECT* const p_dev_obj ) { hca_dev_ext_t *p_ext; - POWER_STATE powerState; + POWER_STATE powerState; HCA_ENTER( HCA_DBG_PNP ); @@ -988,8 +1000,14 @@ hca_release_resources( __hca_release_resources(p_dev_obj); /* Notify the power manager that the device is powered down. */ + p_ext->DevicePowerState = PowerDeviceD3; powerState.DeviceState = PowerDeviceD3; - PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState ); + powerState = PoSetPowerState ( p_ext->cl_ext.p_self_do, DevicePowerState, powerState ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PNP, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_ext->DevicePowerState )); + /* Clear the PnP state in case we get restarted. */ p_ext->pnpState = 0; @@ -1246,7 +1264,6 @@ hca_query_pnp_state( return STATUS_SUCCESS;; } - static NTSTATUS hca_query_power( IN DEVICE_OBJECT* const p_dev_obj, @@ -1262,15 +1279,30 @@ hca_query_power( pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("QUERY_POWER for FDO %p: type %s, state %d, action %d, IRQL %d, IRP %p\n", + p_dev_obj, + (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + pIoStack->Parameters.Power.State.DeviceState, + pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql(), p_irp )); + switch( pIoStack->Parameters.Power.Type ) { case SystemPowerState: /* Fail any requests to hibernate or sleep the system. */ switch( pIoStack->Parameters.Power.State.SystemState ) { + case PowerSystemSleeping1: // STANDBY support + case PowerSystemHibernate: + { + hca_dev_ext_t*p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; + if (atomic_read(&p_ext->usecnt)) + status = STATUS_UNSUCCESSFUL; + break; + } + case PowerSystemWorking: case PowerSystemShutdown: - /* We only support fully working and shutdown system states. */ break; default: @@ -1293,10 +1325,10 @@ hca_query_power( break; } - if( status == STATUS_NOT_SUPPORTED ) - *p_action = IrpComplete; - else + if( status == STATUS_SUCCESS ) *p_action = IrpSkip; + else + *p_action = IrpComplete; HCA_EXIT( HCA_DBG_PO ); return status; @@ -1345,7 +1377,7 @@ __SystemPowerCompletion( hca_dev_ext_t *p_ext; IO_STACK_LOCATION *pIoStack; - HCA_ENTER( HCA_DBG_PNP ); + HCA_ENTER( HCA_DBG_PO ); UNUSED_PARAM( context ); @@ -1354,12 +1386,12 @@ __SystemPowerCompletion( if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) { - PoStartNextPowerIrp( p_irp ); - IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); - HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, ("IRP_MN_SET_POWER for system failed by lower driver with %08x.\n", p_irp->IoStatus.Status)); - return STATUS_SUCCESS; + status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + goto release; } state.DeviceState = @@ -1372,25 +1404,33 @@ __SystemPowerCompletion( status = PoRequestPowerIrp( p_dev_obj, IRP_MN_SET_POWER, state, __RequestPowerCompletion, p_irp, NULL ); - if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) - { + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("PoRequestPowerIrp: SET_POWER 'PowerDeviceD%d', status %#x\n", + state.DeviceState - 1, status )); + + if( status != STATUS_PENDING ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("PoRequestPowerIrp returned %08x.\n", status)); + p_irp->IoStatus.Status = status; /* Propagate the failure. */ PoStartNextPowerIrp( p_irp ); - /* Propagate the failure. */ - p_irp->IoStatus.Status = status; IoCompleteRequest( p_irp, IO_NO_INCREMENT ); - IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); - HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, - ("PoRequestPowerIrp returned %08x.\n", status)); + goto release; } - HCA_EXIT( HCA_DBG_PNP ); - return STATUS_MORE_PROCESSING_REQUIRED; + status = STATUS_MORE_PROCESSING_REQUIRED; + goto exit; + +release: + IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); +exit: + HCA_EXIT( HCA_DBG_PO ); + return status; } /* Work item callback to handle DevicePowerD0 IRPs at passive level. */ static void -__PowerUpCb( +__DevicePowerUpCompletionWorkItem( IN DEVICE_OBJECT* p_dev_obj, IN void* context ) { @@ -1398,6 +1438,7 @@ __PowerUpCb( IO_STACK_LOCATION *pIoStack; hca_dev_ext_t *p_ext; IRP *p_irp; + POWER_STATE powerState; HCA_ENTER( HCA_DBG_PO ); @@ -1409,32 +1450,50 @@ __PowerUpCb( p_ext->pPoWorkItem = NULL; /* restart the HCA */ + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("***** Restart the HCA, IRQL %d\n", KeGetCurrentIrql())); + status = mthca_init_one( p_ext ); - if( !NT_SUCCESS( status ) ) - goto done; + if( !NT_SUCCESS( status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("!!! mthca_init_one failed (%#x) \n", status)); + goto err_mthca_init; + } - if( p_ext->p_al_dev ) + if( p_ext->p_al_dev ) { status = __hca_register( p_dev_obj ); - -done: - if( !NT_SUCCESS( status ) ) - { - /* Flag device as having failed. */ - p_ext->pnpState |= PNP_DEVICE_FAILED; - IoInvalidateDeviceState( p_ext->cl_ext.p_pdo ); + if( !NT_SUCCESS( status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("!!! __hca_register failed (%#x) \n", status)); + goto err_hca_reg; + } } + p_ext->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState; + powerState = PoSetPowerState( p_dev_obj, DevicePowerState, + pIoStack->Parameters.Power.State ); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("PoSetPowerState: old state %d, new state to %d\n", + powerState.DeviceState, p_ext->DevicePowerState )); + + goto exit; + +err_hca_reg: +err_mthca_init: + /* Flag device as having failed. */ + p_ext->pnpState |= PNP_DEVICE_FAILED; + IoInvalidateDeviceState( p_ext->cl_ext.p_pdo ); +exit: PoStartNextPowerIrp( p_irp ); IoCompleteRequest( p_irp, IO_NO_INCREMENT ); IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); - HCA_EXIT( HCA_DBG_PO ); } - /*NOTE: Completion routines must NEVER be pageable. */ static NTSTATUS -__DevicePowerCompletion( +__DevicePowerUpCompletion( IN DEVICE_OBJECT *p_dev_obj, IN IRP *p_irp, IN void *context ) @@ -1442,9 +1501,6 @@ __DevicePowerCompletion( NTSTATUS status = STATUS_SUCCESS; hca_dev_ext_t *p_ext; IO_STACK_LOCATION *pIoStack; - KIRQL irql = KeGetCurrentIrql( ); - - HCA_ENTER( HCA_DBG_PO ); @@ -1453,61 +1509,43 @@ __DevicePowerCompletion( p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; pIoStack = IoGetCurrentIrpStackLocation( p_irp ); - if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) - { - PoStartNextPowerIrp( p_irp ); - IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); - HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, + if( !NT_SUCCESS( p_irp->IoStatus.Status ) ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, ("IRP_MN_SET_POWER for device failed by lower driver with %08x.\n", p_irp->IoStatus.Status)); - return STATUS_SUCCESS; - } - - p_ext->PowerState = pIoStack->Parameters.Power.State.DeviceState; - PoSetPowerState( p_dev_obj, DevicePowerState, - pIoStack->Parameters.Power.State ); - - if (irql > PASSIVE_LEVEL) { - /* Process in a work item - mthca_start blocks. */ - ASSERT( !p_ext->pPoWorkItem ); - p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj ); - if( !p_ext->pPoWorkItem ) - { - IoInvalidateDeviceState( p_ext->cl_ext.p_pdo ); - - PoStartNextPowerIrp( p_irp ); - IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); - - return STATUS_SUCCESS; - } - - /* Process in work item callback. */ - IoMarkIrpPending( p_irp ); - IoQueueWorkItem( p_ext->pPoWorkItem, __PowerUpCb, DelayedWorkQueue, p_irp ); + status = STATUS_SUCCESS; + PoStartNextPowerIrp( p_irp ); + goto release; } - else { - - /* restart the HCA */ - status = mthca_init_one( p_ext ); - if( !NT_SUCCESS( status ) ) - goto done; - if( p_ext->p_al_dev ) - status = __hca_register( p_dev_obj ); + /* Process in a work item - mthca_start blocks. */ + ASSERT( !p_ext->pPoWorkItem ); + p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj ); + if( !p_ext->pPoWorkItem ) { + HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PO, + ("Failed to allocate work item.\n" )); + status = STATUS_SUCCESS; + p_ext->pnpState |= PNP_DEVICE_FAILED; + IoInvalidateDeviceState( p_ext->cl_ext.p_pdo ); + PoStartNextPowerIrp( p_irp ); + goto release; } -done: - if( !NT_SUCCESS( status ) ) - IoInvalidateDeviceState( p_ext->cl_ext.p_pdo ); + /* Process in work item callback. */ + IoMarkIrpPending( p_irp ); + IoQueueWorkItem( p_ext->pPoWorkItem, + __DevicePowerUpCompletionWorkItem, DelayedWorkQueue, p_irp ); + status = STATUS_MORE_PROCESSING_REQUIRED; + goto exit; - PoStartNextPowerIrp( p_irp ); +release: IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); - +exit: HCA_EXIT( HCA_DBG_PO ); - return STATUS_MORE_PROCESSING_REQUIRED; + return status; } -static NTSTATUS __DeviceDownCbCompletion( +static NTSTATUS __DevicePowerDownWorkItemCompletion( IN DEVICE_OBJECT *p_dev_obj, IN IRP *p_irp, IN void *context ) @@ -1515,20 +1553,25 @@ static NTSTATUS __DeviceDownCbCompletion( hca_dev_ext_t *p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; UNUSED_PARAM( context ); + HCA_ENTER( HCA_DBG_PO ); + PoStartNextPowerIrp( p_irp ); IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp ); + + HCA_EXIT( HCA_DBG_PO ); return STATUS_SUCCESS; } /* Work item callback to handle DevicePowerD3 IRPs at passive level. */ static void -__PowerDownCb( +__DevicePowerDownWorkItem( IN DEVICE_OBJECT* p_dev_obj, IN void* context ) { IO_STACK_LOCATION *pIoStack; hca_dev_ext_t *p_ext; IRP *p_irp; + POWER_STATE powerState; HCA_ENTER( HCA_DBG_PO ); @@ -1539,15 +1582,25 @@ __PowerDownCb( IoFreeWorkItem( p_ext->pPoWorkItem ); p_ext->pPoWorkItem = NULL; - PoSetPowerState( p_dev_obj, DevicePowerState, + p_ext->DevicePowerState = pIoStack->Parameters.Power.State.DeviceState; + powerState = PoSetPowerState( p_dev_obj, DevicePowerState, pIoStack->Parameters.Power.State ); - __hca_deregister( p_ext ); - mthca_remove_one( p_ext ); + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("PoSetPowerState: old state %d, new state to %d, IRQL %d\n", + powerState.DeviceState, p_ext->DevicePowerState, KeGetCurrentIrql() )); + + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("***** Remove the HCA \n")); + + { + __hca_deregister( p_ext ); + mthca_remove_one( p_ext ); + } IoCopyCurrentIrpStackLocationToNext( p_irp ); #pragma warning( push, 3 ) - IoSetCompletionRoutine( p_irp, __DeviceDownCbCompletion, + IoSetCompletionRoutine( p_irp, __DevicePowerDownWorkItemCompletion, NULL, TRUE, TRUE, TRUE ); #pragma warning( pop ) PoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); @@ -1571,9 +1624,18 @@ hca_set_power( p_ext = (hca_dev_ext_t*)p_dev_obj->DeviceExtension; pIoStack = IoGetCurrentIrpStackLocation( p_irp ); + HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_PO, + ("SET_POWER for FDO %p (ext %p): type %s, state %d, action %d, IRQL %d \n", + p_dev_obj, p_ext, + (pIoStack->Parameters.Power.Type) ? "DevicePowerState" : "SystemPowerState", + pIoStack->Parameters.Power.State.DeviceState, + pIoStack->Parameters.Power.ShutdownType, KeGetCurrentIrql() )); + switch( pIoStack->Parameters.Power.Type ) { case SystemPowerState: + p_ext->SystemPowerState = pIoStack->Parameters.Power.State.SystemState; + /* * Process on the way up the stack. We cannot block since the * power dispatch function can be called at elevated IRQL if the @@ -1593,10 +1655,11 @@ hca_set_power( case DevicePowerState: IoMarkIrpPending( p_irp ); - if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 ) - { + if( pIoStack->Parameters.Power.State.DeviceState == PowerDeviceD0 && + p_ext->SystemPowerState == PowerSystemWorking) + { /* power up */ /* If we're already powered up, just pass down. */ - if( p_ext->PowerState == PowerDeviceD0 ) + if( p_ext->DevicePowerState == PowerDeviceD0 ) { status = STATUS_SUCCESS; *p_action = IrpIgnore; @@ -1606,13 +1669,14 @@ hca_set_power( /* Process in I/O completion callback. */ IoCopyCurrentIrpStackLocationToNext( p_irp ); #pragma warning( push, 3 ) - IoSetCompletionRoutine( p_irp, __DevicePowerCompletion, NULL, + IoSetCompletionRoutine( p_irp, __DevicePowerUpCompletion, NULL, TRUE, TRUE, TRUE ); #pragma warning( pop ) PoCallDriver( p_ext->cl_ext.p_next_do, p_irp ); } else - { + { /* power down */ + /* Process in a work item - deregister_ca and HcaDeinit block. */ ASSERT( !p_ext->pPoWorkItem ); p_ext->pPoWorkItem = IoAllocateWorkItem( p_dev_obj ); @@ -1623,9 +1687,8 @@ hca_set_power( } /* Process in work item callback. */ - IoMarkIrpPending( p_irp ); IoQueueWorkItem( - p_ext->pPoWorkItem, __PowerDownCb, DelayedWorkQueue, p_irp ); + p_ext->pPoWorkItem, __DevicePowerDownWorkItem, DelayedWorkQueue, p_irp ); } *p_action = IrpDoNothing; status = STATUS_PENDING; diff --git a/trunk/hw/mthca/kernel/mthca_cmd.c b/trunk/hw/mthca/kernel/mthca_cmd.c index 7ecba1b2..2ea169d4 100644 --- a/trunk/hw/mthca/kernel/mthca_cmd.c +++ b/trunk/hw/mthca/kernel/mthca_cmd.c @@ -383,8 +383,11 @@ static int mthca_cmd_wait(struct mthca_dev *dev, out_param ? *out_param : 0, in_modifier, op_modifier, op, context->token, 1); - if (err) + if (err) { + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_LOW, + ("mthca_cmd_wait: Command %02x completed with err %02x\n", op, err)); goto out; + } { NTSTATUS res; @@ -393,13 +396,15 @@ static int mthca_cmd_wait(struct mthca_dev *dev, res = KeWaitForSingleObject( &context->event, Executive, KernelMode, FALSE, &interval ); if (res != STATUS_SUCCESS) { err = -EBUSY; + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_LOW, + ("mthca_cmd_wait: Command %02x completed with err %02x\n", op, err)); goto out; } } *status = context->status; if (*status) - HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("mthca_cmd_wait: Command %02x completed with status %02x\n", + HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_LOW,("mthca_cmd_wait: Command %02x completed with status %02x\n", op, *status)); if (out_is_imm)