@ -48,40 +48,40 @@ uint32_t spapr_drc_index(sPAPRDRConnector *drc)
static uint32_t drc_isolate_physical ( sPAPRDRConnector * drc )
{
/* if the guest is configuring a device attached to this DRC, we
* should reset the configuration state at this point since it may
* no longer be reliable ( guest released device and needs to start
* over , or unplug occurred so the FDT is no longer valid )
*/
g_free ( drc - > ccs ) ;
drc - > ccs = NULL ;
switch ( drc - > state ) {
case SPAPR_DRC_STATE_PHYSICAL_POWERON :
return RTAS_OUT_SUCCESS ; /* Nothing to do */
case SPAPR_DRC_STATE_PHYSICAL_CONFIGURED :
break ; /* see below */
case SPAPR_DRC_STATE_PHYSICAL_UNISOLATE :
return RTAS_OUT_PARAM_ERROR ; /* not allowed */
default :
g_assert_not_reached ( ) ;
}
drc - > isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED ;
drc - > state = SPAPR_DRC_STATE_PHYSICAL_POWERON ;
/* if we're awaiting release, but still in an unconfigured state,
* it ' s likely the guest is still in the process of configuring
* the device and is transitioning the devices to an ISOLATED
* state as a part of that process . so we only complete the
* removal when this transition happens for a device in a
* configured state , as suggested by the state diagram from PAPR +
* 2.7 , 13.4
*/
if ( drc - > awaiting_release ) {
if ( drc - > unplug_requested ) {
uint32_t drc_index = spapr_drc_index ( drc ) ;
if ( drc - > configured ) {
trace_spapr_drc_set_isolation_state_finalizing ( drc_index ) ;
spapr_drc_detach ( drc , DEVICE ( drc - > dev ) , NULL ) ;
} else {
trace_spapr_drc_set_isolation_state_deferring ( drc_index ) ;
}
trace_spapr_drc_set_isolation_state_finalizing ( drc_index ) ;
spapr_drc_detach ( drc ) ;
}
drc - > configured = false ;
return RTAS_OUT_SUCCESS ;
}
static uint32_t drc_unisolate_physical ( sPAPRDRConnector * drc )
{
switch ( drc - > state ) {
case SPAPR_DRC_STATE_PHYSICAL_UNISOLATE :
case SPAPR_DRC_STATE_PHYSICAL_CONFIGURED :
return RTAS_OUT_SUCCESS ; /* Nothing to do */
case SPAPR_DRC_STATE_PHYSICAL_POWERON :
break ; /* see below */
default :
g_assert_not_reached ( ) ;
}
/* cannot unisolate a non-existent resource, and, or resources
* which are in an ' UNUSABLE ' allocation state . ( PAPR 2.7 ,
* 13.5 .3 .5 )
@ -90,20 +90,26 @@ static uint32_t drc_unisolate_physical(sPAPRDRConnector *drc)
return RTAS_OUT_NO_SUCH_INDICATOR ;
}
drc - > isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED ;
drc - > state = SPAPR_DRC_STATE_PHYSICAL_UNISOLATE ;
drc - > ccs_offset = drc - > fdt_start_offset ;
drc - > ccs_depth = 0 ;
return RTAS_OUT_SUCCESS ;
}
static uint32_t drc_isolate_logical ( sPAPRDRConnector * drc )
{
/* if the guest is configuring a device attached to this DRC, we
* should reset the configuration state at this point since it may
* no longer be reliable ( guest released device and needs to start
* over , or unplug occurred so the FDT is no longer valid )
*/
g_free ( drc - > ccs ) ;
drc - > ccs = NULL ;
switch ( drc - > state ) {
case SPAPR_DRC_STATE_LOGICAL_AVAILABLE :
case SPAPR_DRC_STATE_LOGICAL_UNUSABLE :
return RTAS_OUT_SUCCESS ; /* Nothing to do */
case SPAPR_DRC_STATE_LOGICAL_CONFIGURED :
break ; /* see below */
case SPAPR_DRC_STATE_LOGICAL_UNISOLATE :
return RTAS_OUT_PARAM_ERROR ; /* not allowed */
default :
g_assert_not_reached ( ) ;
}
/*
* Fail any requests to ISOLATE the LMB DRC if this LMB doesn ' t
@ -116,11 +122,11 @@ static uint32_t drc_isolate_logical(sPAPRDRConnector *drc)
* actually being unplugged , fail the isolation request here .
*/
if ( spapr_drc_type ( drc ) = = SPAPR_DR_CONNECTOR_TYPE_LMB
& & ! drc - > awaiting_release ) {
& & ! drc - > unplug_requested ) {
return RTAS_OUT_HW_ERROR ;
}
drc - > isolation_ state = SPAPR_DR_ISOLATION_STATE_ISOLATED ;
drc - > state = SPAPR_DRC_STATE_LOGICAL_AVAILABLE ;
/* if we're awaiting release, but still in an unconfigured state,
* it ' s likely the guest is still in the process of configuring
@ -130,38 +136,51 @@ static uint32_t drc_isolate_logical(sPAPRDRConnector *drc)
* configured state , as suggested by the state diagram from PAPR +
* 2.7 , 13.4
*/
if ( drc - > awaiting_release ) {
if ( drc - > unplug_requested ) {
uint32_t drc_index = spapr_drc_index ( drc ) ;
if ( drc - > configured ) {
trace_spapr_drc_set_isolation_state_finalizing ( drc_index ) ;
spapr_drc_detach ( drc , DEVICE ( drc - > dev ) , NULL ) ;
} else {
trace_spapr_drc_set_isolation_state_deferring ( drc_index ) ;
}
trace_spapr_drc_set_isolation_state_finalizing ( drc_index ) ;
spapr_drc_detach ( drc ) ;
}
drc - > configured = false ;
return RTAS_OUT_SUCCESS ;
}
static uint32_t drc_unisolate_logical ( sPAPRDRConnector * drc )
{
/* cannot unisolate a non-existent resource, and, or resources
* which are in an ' UNUSABLE ' allocation state . ( PAPR 2.7 ,
* 13.5 .3 .5 )
*/
if ( ! drc - > dev | |
drc - > allocation_state = = SPAPR_DR_ALLOCATION_STATE_UNUSABLE ) {
return RTAS_OUT_NO_SUCH_INDICATOR ;
switch ( drc - > state ) {
case SPAPR_DRC_STATE_LOGICAL_UNISOLATE :
case SPAPR_DRC_STATE_LOGICAL_CONFIGURED :
return RTAS_OUT_SUCCESS ; /* Nothing to do */
case SPAPR_DRC_STATE_LOGICAL_AVAILABLE :
break ; /* see below */
case SPAPR_DRC_STATE_LOGICAL_UNUSABLE :
return RTAS_OUT_NO_SUCH_INDICATOR ; /* not allowed */
default :
g_assert_not_reached ( ) ;
}
drc - > isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED ;
/* Move to AVAILABLE state should have ensured device was present */
g_assert ( drc - > dev ) ;
drc - > state = SPAPR_DRC_STATE_LOGICAL_UNISOLATE ;
drc - > ccs_offset = drc - > fdt_start_offset ;
drc - > ccs_depth = 0 ;
return RTAS_OUT_SUCCESS ;
}
static uint32_t drc_set_usable ( sPAPRDRConnector * drc )
{
switch ( drc - > state ) {
case SPAPR_DRC_STATE_LOGICAL_AVAILABLE :
case SPAPR_DRC_STATE_LOGICAL_UNISOLATE :
case SPAPR_DRC_STATE_LOGICAL_CONFIGURED :
return RTAS_OUT_SUCCESS ; /* Nothing to do */
case SPAPR_DRC_STATE_LOGICAL_UNUSABLE :
break ; /* see below */
default :
g_assert_not_reached ( ) ;
}
/* if there's no resource/device associated with the DRC, there's
* no way for us to put it in an allocation state consistent with
* being ' USABLE ' . PAPR 2.7 , 13.5 .3 .4 documents that this should
@ -170,30 +189,36 @@ static uint32_t drc_set_usable(sPAPRDRConnector *drc)
if ( ! drc - > dev ) {
return RTAS_OUT_NO_SUCH_INDICATOR ;
}
if ( drc - > awaiting_release & & drc - > awaiting_allocation ) {
/* kernel is acknowledging a previous hotplug event
* while we are already removing it .
* it ' s safe to ignore awaiting_allocation here since we know the
* situation is predicated on the guest either already having done
* so ( boot - time hotplug ) , or never being able to acquire in the
* first place ( hotplug followed by immediate unplug ) .
*/
if ( drc - > unplug_requested ) {
/* Don't allow the guest to move a device away from UNUSABLE
* state when we want to unplug it */
return RTAS_OUT_NO_SUCH_INDICATOR ;
}
drc - > allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE ;
drc - > awaiting_allocation = false ;
drc - > state = SPAPR_DRC_STATE_LOGICAL_AVAILABLE ;
return RTAS_OUT_SUCCESS ;
}
static uint32_t drc_set_unusable ( sPAPRDRConnector * drc )
{
drc - > allocation_state = SPAPR_DR_ALLOCATION_STATE_UNUSABLE ;
if ( drc - > awaiting_release ) {
switch ( drc - > state ) {
case SPAPR_DRC_STATE_LOGICAL_UNUSABLE :
return RTAS_OUT_SUCCESS ; /* Nothing to do */
case SPAPR_DRC_STATE_LOGICAL_AVAILABLE :
break ; /* see below */
case SPAPR_DRC_STATE_LOGICAL_UNISOLATE :
case SPAPR_DRC_STATE_LOGICAL_CONFIGURED :
return RTAS_OUT_NO_SUCH_INDICATOR ; /* not allowed */
default :
g_assert_not_reached ( ) ;
}
drc - > state = SPAPR_DRC_STATE_LOGICAL_UNUSABLE ;
if ( drc - > unplug_requested ) {
uint32_t drc_index = spapr_drc_index ( drc ) ;
trace_spapr_drc_set_allocation_state_finalizing ( drc_index ) ;
spapr_drc_detach ( drc , DEVICE ( drc - > dev ) , NULL ) ;
spapr_drc_detach ( drc ) ;
}
return RTAS_OUT_SUCCESS ;
@ -247,11 +272,16 @@ static sPAPRDREntitySense physical_entity_sense(sPAPRDRConnector *drc)
static sPAPRDREntitySense logical_entity_sense ( sPAPRDRConnector * drc )
{
if ( drc - > dev
& & ( drc - > allocation_state ! = SPAPR_DR_ALLOCATION_STATE_UNUSABLE ) ) {
return SPAPR_DR_ENTITY_SENSE_PRESENT ;
} else {
switch ( drc - > state ) {
case SPAPR_DRC_STATE_LOGICAL_UNUSABLE :
return SPAPR_DR_ENTITY_SENSE_UNUSABLE ;
case SPAPR_DRC_STATE_LOGICAL_AVAILABLE :
case SPAPR_DRC_STATE_LOGICAL_UNISOLATE :
case SPAPR_DRC_STATE_LOGICAL_CONFIGURED :
g_assert ( drc - > dev ) ;
return SPAPR_DR_ENTITY_SENSE_PRESENT ;
default :
g_assert_not_reached ( ) ;
}
}
@ -344,23 +374,18 @@ void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
{
trace_spapr_drc_attach ( spapr_drc_index ( drc ) ) ;
if ( drc - > isolation_state ! = SPAPR_DR_ISOLATION_STATE_ISOLATED ) {
if ( drc - > dev ) {
error_setg ( errp , " an attached device is still awaiting release " ) ;
return ;
}
if ( spapr_drc_type ( drc ) = = SPAPR_DR_CONNECTOR_TYPE_PCI ) {
g_assert ( drc - > allocation_state = = SPAPR_DR_ALLOCATION_STATE_USABLE ) ;
}
g_assert ( ( drc - > state = = SPAPR_DRC_STATE_LOGICAL_UNUSABLE )
| | ( drc - > state = = SPAPR_DRC_STATE_PHYSICAL_POWERON ) ) ;
g_assert ( fdt ) ;
drc - > dev = d ;
drc - > fdt = fdt ;
drc - > fdt_start_offset = fdt_start_offset ;
if ( spapr_drc_type ( drc ) ! = SPAPR_DR_CONNECTOR_TYPE_PCI ) {
drc - > awaiting_allocation = true ;
}
object_property_add_link ( OBJECT ( drc ) , " device " ,
object_get_typename ( OBJECT ( drc - > dev ) ) ,
( Object * * ) ( & drc - > dev ) ,
@ -373,85 +398,65 @@ static void spapr_drc_release(sPAPRDRConnector *drc)
drck - > release ( drc - > dev ) ;
drc - > awaiting_release = false ;
drc - > unplug_requested = false ;
g_free ( drc - > fdt ) ;
drc - > fdt = NULL ;
drc - > fdt_start_offset = 0 ;
object_property_del ( OBJECT ( drc ) , " device " , NULL ) ;
object_property_del ( OBJECT ( drc ) , " device " , & error_abort ) ;
drc - > dev = NULL ;
}
void spapr_drc_detach ( sPAPRDRConnector * drc , DeviceState * d , Error * * errp )
void spapr_drc_detach ( sPAPRDRConnector * drc )
{
sPAPRDRConnectorClass * drck = SPAPR_DR_CONNECTOR_GET_CLASS ( drc ) ;
trace_spapr_drc_detach ( spapr_drc_index ( drc ) ) ;
if ( drc - > isolation_state ! = SPAPR_DR_ISOLATION_STATE_ISOLATED ) {
trace_spapr_drc_awaiting_isolated ( spapr_drc_index ( drc ) ) ;
drc - > awaiting_release = true ;
return ;
}
g_assert ( drc - > dev ) ;
if ( spapr_drc_type ( drc ) ! = SPAPR_DR_CONNECTOR_TYPE_PCI & &
drc - > allocation_state ! = SPAPR_DR_ALLOCATION_STATE_UNUSABLE ) {
trace_spapr_drc_awaiting_unusable ( spapr_drc_index ( drc ) ) ;
drc - > awaiting_release = true ;
return ;
}
drc - > unplug_requested = true ;
if ( drc - > awaiting_allocation ) {
drc - > awaiting_release = true ;
trace_spapr_drc_awaiting_allocation ( spapr_drc_index ( drc ) ) ;
if ( drc - > state ! = drck - > empty_state ) {
trace_spapr_drc_awaiting_quiesce ( spapr_drc_index ( drc ) ) ;
return ;
}
spapr_drc_release ( drc ) ;
}
static bool release_pending ( sPAPRDRConnector * drc )
void spapr_drc_reset ( sPAPRDRConnector * drc )
{
return drc - > awaiting_release ;
}
static void drc_reset ( void * opaque )
{
sPAPRDRConnector * drc = SPAPR_DR_CONNECTOR ( opaque ) ;
sPAPRDRConnectorClass * drck = SPAPR_DR_CONNECTOR_GET_CLASS ( drc ) ;
trace_spapr_drc_reset ( spapr_drc_index ( drc ) ) ;
g_free ( drc - > ccs ) ;
drc - > ccs = NULL ;
/* immediately upon reset we can safely assume DRCs whose devices
* are pending removal can be safely removed .
*/
if ( drc - > awaiting_release ) {
if ( drc - > unplug_requested ) {
spapr_drc_release ( drc ) ;
}
drc - > awaiting_allocation = false ;
if ( drc - > dev ) {
/* A device present at reset is coldplugged */
drc - > isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED ;
if ( spapr_drc_type ( drc ) ! = SPAPR_DR_CONNECTOR_TYPE_PCI ) {
drc - > allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE ;
}
drc - > dr_indicator = SPAPR_DR_INDICATOR_ACTIVE ;
/* A device present at reset is ready to go, same as coldplugged */
drc - > state = drck - > ready_state ;
} else {
/* Otherwise device is absent, but might be hotplugged */
drc - > isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED ;
if ( spapr_drc_type ( drc ) ! = SPAPR_DR_CONNECTOR_TYPE_PCI ) {
drc - > allocation_state = SPAPR_DR_ALLOCATION_STATE_UNUSABLE ;
}
drc - > dr_indicator = SPAPR_DR_INDICATOR_INACTIVE ;
drc - > state = drck - > empty_state ;
}
drc - > ccs_offset = - 1 ;
drc - > ccs_depth = - 1 ;
}
static void drc_reset ( void * opaque )
{
spapr_drc_reset ( SPAPR_DR_CONNECTOR ( opaque ) ) ;
}
static bool spapr_drc_needed ( void * opaque )
{
sPAPRDRConnector * drc = ( sPAPRDRConnector * ) opaque ;
sPAPRDRConnectorClass * drck = SPAPR_DR_CONNECTOR_GET_CLASS ( drc ) ;
bool rc = false ;
sPAPRDREntitySense value = drck - > dr_entity_sense ( drc ) ;
/* If no dev is plugged in there is no need to migrate the DRC state */
@ -460,23 +465,10 @@ static bool spapr_drc_needed(void *opaque)
}
/*
* If there is dev plugged in , we need to migrate the DRC state when
* it is different from cold - plugged state
*/
switch ( spapr_drc_type ( drc ) ) {
case SPAPR_DR_CONNECTOR_TYPE_PCI :
case SPAPR_DR_CONNECTOR_TYPE_CPU :
case SPAPR_DR_CONNECTOR_TYPE_LMB :
rc = ! ( ( drc - > isolation_state = = SPAPR_DR_ISOLATION_STATE_UNISOLATED ) & &
( drc - > allocation_state = = SPAPR_DR_ALLOCATION_STATE_USABLE ) & &
drc - > configured & & ! drc - > awaiting_release ) ;
break ;
case SPAPR_DR_CONNECTOR_TYPE_PHB :
case SPAPR_DR_CONNECTOR_TYPE_VIO :
default :
g_assert_not_reached ( ) ;
}
return rc ;
* We need to migrate the state if it ' s not equal to the expected
* long - term state , which is the same as the coldplugged initial
* state */
return ( drc - > state ! = drck - > ready_state ) ;
}
static const VMStateDescription vmstate_spapr_drc = {
@ -485,12 +477,7 @@ static const VMStateDescription vmstate_spapr_drc = {
. minimum_version_id = 1 ,
. needed = spapr_drc_needed ,
. fields = ( VMStateField [ ] ) {
VMSTATE_UINT32 ( isolation_state , sPAPRDRConnector ) ,
VMSTATE_UINT32 ( allocation_state , sPAPRDRConnector ) ,
VMSTATE_UINT32 ( dr_indicator , sPAPRDRConnector ) ,
VMSTATE_BOOL ( configured , sPAPRDRConnector ) ,
VMSTATE_BOOL ( awaiting_release , sPAPRDRConnector ) ,
VMSTATE_BOOL ( awaiting_allocation , sPAPRDRConnector ) ,
VMSTATE_UINT32 ( state , sPAPRDRConnector ) ,
VMSTATE_END_OF_LIST ( )
}
} ;
@ -559,46 +546,96 @@ sPAPRDRConnector *spapr_dr_connector_new(Object *owner, const char *type,
object_property_set_bool ( OBJECT ( drc ) , true , " realized " , NULL ) ;
g_free ( prop_name ) ;
/* PCI slot always start in a USABLE state, and stay there */
if ( spapr_drc_type ( drc ) = = SPAPR_DR_CONNECTOR_TYPE_PCI ) {
drc - > allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE ;
}
return drc ;
}
static void spapr_dr_connector_instance_init ( Object * obj )
{
sPAPRDRConnector * drc = SPAPR_DR_CONNECTOR ( obj ) ;
sPAPRDRConnectorClass * drck = SPAPR_DR_CONNECTOR_GET_CLASS ( drc ) ;
object_property_add_uint32_ptr ( obj , " id " , & drc - > id , NULL ) ;
object_property_add ( obj , " index " , " uint32 " , prop_get_index ,
NULL , NULL , NULL , NULL ) ;
object_property_add ( obj , " fdt " , " struct " , prop_get_fdt ,
NULL , NULL , NULL , NULL ) ;
drc - > state = drck - > empty_state ;
}
static void spapr_dr_connector_class_init ( ObjectClass * k , void * data )
{
DeviceClass * dk = DEVICE_CLASS ( k ) ;
sPAPRDRConnectorClass * drck = SPAPR_DR_CONNECTOR_CLASS ( k ) ;
dk - > realize = realize ;
dk - > unrealize = unrealize ;
drck - > release_pending = release_pending ;
/*
* Reason : it crashes FIXME find and document the real reason
*/
dk - > user_creatable = false ;
}
static bool drc_physical_needed ( void * opaque )
{
sPAPRDRCPhysical * drcp = ( sPAPRDRCPhysical * ) opaque ;
sPAPRDRConnector * drc = SPAPR_DR_CONNECTOR ( drcp ) ;
if ( ( drc - > dev & & ( drcp - > dr_indicator = = SPAPR_DR_INDICATOR_ACTIVE ) )
| | ( ! drc - > dev & & ( drcp - > dr_indicator = = SPAPR_DR_INDICATOR_INACTIVE ) ) ) {
return false ;
}
return true ;
}
static const VMStateDescription vmstate_spapr_drc_physical = {
. name = " spapr_drc/physical " ,
. version_id = 1 ,
. minimum_version_id = 1 ,
. needed = drc_physical_needed ,
. fields = ( VMStateField [ ] ) {
VMSTATE_UINT32 ( dr_indicator , sPAPRDRCPhysical ) ,
VMSTATE_END_OF_LIST ( )
}
} ;
static void drc_physical_reset ( void * opaque )
{
sPAPRDRConnector * drc = SPAPR_DR_CONNECTOR ( opaque ) ;
sPAPRDRCPhysical * drcp = SPAPR_DRC_PHYSICAL ( drc ) ;
if ( drc - > dev ) {
drcp - > dr_indicator = SPAPR_DR_INDICATOR_ACTIVE ;
} else {
drcp - > dr_indicator = SPAPR_DR_INDICATOR_INACTIVE ;
}
}
static void realize_physical ( DeviceState * d , Error * * errp )
{
sPAPRDRCPhysical * drcp = SPAPR_DRC_PHYSICAL ( d ) ;
Error * local_err = NULL ;
realize ( d , & local_err ) ;
if ( local_err ) {
error_propagate ( errp , local_err ) ;
return ;
}
vmstate_register ( DEVICE ( drcp ) , spapr_drc_index ( SPAPR_DR_CONNECTOR ( drcp ) ) ,
& vmstate_spapr_drc_physical , drcp ) ;
qemu_register_reset ( drc_physical_reset , drcp ) ;
}
static void spapr_drc_physical_class_init ( ObjectClass * k , void * data )
{
DeviceClass * dk = DEVICE_CLASS ( k ) ;
sPAPRDRConnectorClass * drck = SPAPR_DR_CONNECTOR_CLASS ( k ) ;
dk - > realize = realize_physical ;
drck - > dr_entity_sense = physical_entity_sense ;
drck - > isolate = drc_isolate_physical ;
drck - > unisolate = drc_unisolate_physical ;
drck - > ready_state = SPAPR_DRC_STATE_PHYSICAL_CONFIGURED ;
drck - > empty_state = SPAPR_DRC_STATE_PHYSICAL_POWERON ;
}
static void spapr_drc_logical_class_init ( ObjectClass * k , void * data )
@ -608,6 +645,8 @@ static void spapr_drc_logical_class_init(ObjectClass *k, void *data)
drck - > dr_entity_sense = logical_entity_sense ;
drck - > isolate = drc_isolate_logical ;
drck - > unisolate = drc_unisolate_logical ;
drck - > ready_state = SPAPR_DRC_STATE_LOGICAL_CONFIGURED ;
drck - > empty_state = SPAPR_DRC_STATE_LOGICAL_UNUSABLE ;
}
static void spapr_drc_cpu_class_init ( ObjectClass * k , void * data )
@ -653,7 +692,7 @@ static const TypeInfo spapr_dr_connector_info = {
static const TypeInfo spapr_drc_physical_info = {
. name = TYPE_SPAPR_DRC_PHYSICAL ,
. parent = TYPE_SPAPR_DR_CONNECTOR ,
. instance_size = sizeof ( sPAPRDRConnector ) ,
. instance_size = sizeof ( sPAPRDRCPhysical ) ,
. class_init = spapr_drc_physical_class_init ,
. abstract = true ,
} ;
@ -661,7 +700,6 @@ static const TypeInfo spapr_drc_physical_info = {
static const TypeInfo spapr_drc_logical_info = {
. name = TYPE_SPAPR_DRC_LOGICAL ,
. parent = TYPE_SPAPR_DR_CONNECTOR ,
. instance_size = sizeof ( sPAPRDRConnector ) ,
. class_init = spapr_drc_logical_class_init ,
. abstract = true ,
} ;
@ -669,21 +707,18 @@ static const TypeInfo spapr_drc_logical_info = {
static const TypeInfo spapr_drc_cpu_info = {
. name = TYPE_SPAPR_DRC_CPU ,
. parent = TYPE_SPAPR_DRC_LOGICAL ,
. instance_size = sizeof ( sPAPRDRConnector ) ,
. class_init = spapr_drc_cpu_class_init ,
} ;
static const TypeInfo spapr_drc_pci_info = {
. name = TYPE_SPAPR_DRC_PCI ,
. parent = TYPE_SPAPR_DRC_PHYSICAL ,
. instance_size = sizeof ( sPAPRDRConnector ) ,
. class_init = spapr_drc_pci_class_init ,
} ;
static const TypeInfo spapr_drc_lmb_info = {
. name = TYPE_SPAPR_DRC_LMB ,
. parent = TYPE_SPAPR_DRC_LOGICAL ,
. instance_size = sizeof ( sPAPRDRConnector ) ,
. class_init = spapr_drc_lmb_class_init ,
} ;
@ -896,12 +931,18 @@ static uint32_t rtas_set_dr_indicator(uint32_t idx, uint32_t state)
{
sPAPRDRConnector * drc = spapr_drc_by_index ( idx ) ;
if ( ! drc ) {
return RTAS_OUT_PARAM_ERROR ;
if ( ! drc | | ! object_dynamic_cast ( OBJECT ( drc ) , TYPE_SPAPR_DRC_PHYSICAL ) ) {
return RTAS_OUT_NO_SUCH_INDICATOR ;
}
if ( ( state ! = SPAPR_DR_INDICATOR_INACTIVE )
& & ( state ! = SPAPR_DR_INDICATOR_ACTIVE )
& & ( state ! = SPAPR_DR_INDICATOR_IDENTIFY )
& & ( state ! = SPAPR_DR_INDICATOR_ACTION ) ) {
return RTAS_OUT_PARAM_ERROR ; /* bad state parameter */
}
trace_spapr_drc_set_dr_indicator ( idx , state ) ;
drc - > dr_indicator = state ;
SPAPR_DRC_PHYSICAL ( drc ) - > dr_indicator = state ;
return RTAS_OUT_SUCCESS ;
}
@ -1011,7 +1052,7 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
uint64_t wa_offset ;
uint32_t drc_index ;
sPAPRDRConnector * drc ;
sPAPRConfigureConnectorState * ccs ;
sPAPRDRConnectorClass * drck ;
sPAPRDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE ;
int rc ;
@ -1030,18 +1071,16 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
goto out ;
}
if ( ! drc - > fdt ) {
trace_spapr_rtas_ibm_configure_connector_missing_fdt ( drc_index ) ;
if ( ( drc - > state ! = SPAPR_DRC_STATE_LOGICAL_UNISOLATE )
& & ( drc - > state ! = SPAPR_DRC_STATE_PHYSICAL_UNISOLATE ) ) {
/* Need to unisolate the device before configuring */
rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE ;
goto out ;
}
ccs = drc - > ccs ;
if ( ! ccs ) {
ccs = g_new0 ( sPAPRConfigureConnectorState , 1 ) ;
ccs - > fdt_offset = drc - > fdt_start_offset ;
drc - > ccs = ccs ;
}
g_assert ( drc - > fdt ) ;
drck = SPAPR_DR_CONNECTOR_GET_CLASS ( drc ) ;
do {
uint32_t tag ;
@ -1049,12 +1088,12 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
const struct fdt_property * prop ;
int fdt_offset_next , prop_len ;
tag = fdt_next_tag ( drc - > fdt , ccs - > fdt _offset, & fdt_offset_next ) ;
tag = fdt_next_tag ( drc - > fdt , drc - > ccs _offset, & fdt_offset_next ) ;
switch ( tag ) {
case FDT_BEGIN_NODE :
ccs - > fdt _depth+ + ;
name = fdt_get_name ( drc - > fdt , ccs - > fdt _offset, NULL ) ;
drc - > ccs _depth+ + ;
name = fdt_get_name ( drc - > fdt , drc - > ccs _offset, NULL ) ;
/* provide the name of the next OF node */
wa_offset = CC_VAL_DATA_OFFSET ;
@ -1063,30 +1102,22 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD ;
break ;
case FDT_END_NODE :
ccs - > fdt_depth - - ;
if ( ccs - > fdt_depth = = 0 ) {
sPAPRDRIsolationState state = drc - > isolation_state ;
drc - > ccs_depth - - ;
if ( drc - > ccs_depth = = 0 ) {
uint32_t drc_index = spapr_drc_index ( drc ) ;
/* done sending the device tree, don't need to track
* the state anymore
*/
/* done sending the device tree, move to configured state */
trace_spapr_drc_set_configured ( drc_index ) ;
if ( state = = SPAPR_DR_ISOLATION_STATE_UNISOLATED ) {
drc - > configured = true ;
} else {
/* guest should be not configuring an isolated device */
trace_spapr_drc_set_configured_skipping ( drc_index ) ;
}
g_free ( ccs ) ;
drc - > ccs = NULL ;
ccs = NULL ;
drc - > state = drck - > ready_state ;
drc - > ccs_offset = - 1 ;
drc - > ccs_depth = - 1 ;
resp = SPAPR_DR_CC_RESPONSE_SUCCESS ;
} else {
resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT ;
}
break ;
case FDT_PROP :
prop = fdt_get_property_by_offset ( drc - > fdt , ccs - > fdt _offset,
prop = fdt_get_property_by_offset ( drc - > fdt , drc - > ccs _offset,
& prop_len ) ;
name = fdt_string ( drc - > fdt , fdt32_to_cpu ( prop - > nameoff ) ) ;
@ -1111,8 +1142,8 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
/* keep seeking for an actionable tag */
break ;
}
if ( ccs ) {
ccs - > fdt _offset = fdt_offset_next ;
if ( drc - > ccs_offset > = 0 ) {
drc - > ccs _offset = fdt_offset_next ;
}
} while ( resp = = SPAPR_DR_CC_RESPONSE_CONTINUE ) ;