Index: head/sys/dev/sfxge/common/ef10_impl.h =================================================================== --- head/sys/dev/sfxge/common/ef10_impl.h +++ head/sys/dev/sfxge/common/ef10_impl.h @@ -330,6 +330,12 @@ __in efx_mcdi_feature_id_t id, __out boolean_t *supportedp); +extern void +ef10_mcdi_get_timeout( + __in efx_nic_t *enp, + __in efx_mcdi_req_t *emrp, + __out uint32_t *timeoutp); + #endif /* EFSYS_OPT_MCDI */ /* NVRAM */ Index: head/sys/dev/sfxge/common/ef10_mcdi.c =================================================================== --- head/sys/dev/sfxge/common/ef10_mcdi.c +++ head/sys/dev/sfxge/common/ef10_mcdi.c @@ -108,6 +108,46 @@ emip->emi_new_epoch = B_FALSE; } +/* + * In older firmware all commands are processed in a single thread, so a long + * running command for one PCIe function can block processing for another + * function (see bug 61269). + * + * In newer firmware that supports multithreaded MCDI processing, we can extend + * the timeout for long-running requests which we know firmware may choose to + * process in a background thread. + */ +#define EF10_MCDI_CMD_TIMEOUT_US (10 * 1000 * 1000) +#define EF10_MCDI_CMD_LONG_TIMEOUT_US (60 * 1000 * 1000) + + void +ef10_mcdi_get_timeout( + __in efx_nic_t *enp, + __in efx_mcdi_req_t *emrp, + __out uint32_t *timeoutp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + + switch (emrp->emr_cmd) { + case MC_CMD_POLL_BIST: + case MC_CMD_NVRAM_ERASE: + case MC_CMD_LICENSING_V3: + case MC_CMD_NVRAM_UPDATE_FINISH: + if (encp->enc_fw_verified_nvram_update_required != B_FALSE) { + /* + * Potentially longer running commands, which firmware + * may choose to process in a background thread. + */ + *timeoutp = EF10_MCDI_CMD_LONG_TIMEOUT_US; + break; + } + /* FALLTHRU */ + default: + *timeoutp = EF10_MCDI_CMD_TIMEOUT_US; + break; + } +} + void ef10_mcdi_send_request( __in efx_nic_t *enp, Index: head/sys/dev/sfxge/common/efx.h =================================================================== --- head/sys/dev/sfxge/common/efx.h +++ head/sys/dev/sfxge/common/efx.h @@ -243,6 +243,12 @@ __in efx_nic_t *enp); extern void +efx_mcdi_get_timeout( + __in efx_nic_t *enp, + __in efx_mcdi_req_t *emrp, + __out uint32_t *usec_timeoutp); + +extern void efx_mcdi_request_start( __in efx_nic_t *enp, __in efx_mcdi_req_t *emrp, Index: head/sys/dev/sfxge/common/efx_impl.h =================================================================== --- head/sys/dev/sfxge/common/efx_impl.h +++ head/sys/dev/sfxge/common/efx_impl.h @@ -427,7 +427,10 @@ boolean_t (*emco_poll_response)(efx_nic_t *); void (*emco_read_response)(efx_nic_t *, void *, size_t, size_t); void (*emco_fini)(efx_nic_t *); - efx_rc_t (*emco_feature_supported)(efx_nic_t *, efx_mcdi_feature_id_t, boolean_t *); + efx_rc_t (*emco_feature_supported)(efx_nic_t *, + efx_mcdi_feature_id_t, boolean_t *); + void (*emco_get_timeout)(efx_nic_t *, efx_mcdi_req_t *, + uint32_t *); } efx_mcdi_ops_t; typedef struct efx_mcdi_s { Index: head/sys/dev/sfxge/common/efx_mcdi.c =================================================================== --- head/sys/dev/sfxge/common/efx_mcdi.c +++ head/sys/dev/sfxge/common/efx_mcdi.c @@ -67,6 +67,7 @@ siena_mcdi_read_response, /* emco_read_response */ siena_mcdi_fini, /* emco_fini */ siena_mcdi_feature_supported, /* emco_feature_supported */ + siena_mcdi_get_timeout, /* emco_get_timeout */ }; #endif /* EFSYS_OPT_SIENA */ @@ -81,6 +82,7 @@ ef10_mcdi_read_response, /* emco_read_response */ ef10_mcdi_fini, /* emco_fini */ ef10_mcdi_feature_supported, /* emco_feature_supported */ + ef10_mcdi_get_timeout, /* emco_get_timeout */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ @@ -605,6 +607,17 @@ return (aborted); } + void +efx_mcdi_get_timeout( + __in efx_nic_t *enp, + __in efx_mcdi_req_t *emrp, + __out uint32_t *timeoutp) +{ + const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; + + emcop->emco_get_timeout(enp, emrp, timeoutp); +} + __checkReturn efx_rc_t efx_mcdi_request_errcode( __in unsigned int err) Index: head/sys/dev/sfxge/common/siena_impl.h =================================================================== --- head/sys/dev/sfxge/common/siena_impl.h +++ head/sys/dev/sfxge/common/siena_impl.h @@ -127,6 +127,12 @@ __in efx_mcdi_feature_id_t id, __out boolean_t *supportedp); +extern void +siena_mcdi_get_timeout( + __in efx_nic_t *enp, + __in efx_mcdi_req_t *emrp, + __out uint32_t *timeoutp); + #endif /* EFSYS_OPT_MCDI */ #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD Index: head/sys/dev/sfxge/common/siena_mcdi.c =================================================================== --- head/sys/dev/sfxge/common/siena_mcdi.c +++ head/sys/dev/sfxge/common/siena_mcdi.c @@ -247,4 +247,19 @@ return (rc); } +/* Default timeout for MCDI command processing. */ +#define SIENA_MCDI_CMD_TIMEOUT_US (10 * 1000 * 1000) + + void +siena_mcdi_get_timeout( + __in efx_nic_t *enp, + __in efx_mcdi_req_t *emrp, + __out uint32_t *timeoutp) +{ + _NOTE(ARGUNUSED(enp, emrp)) + + *timeoutp = SIENA_MCDI_CMD_TIMEOUT_US; +} + + #endif /* EFSYS_OPT_SIENA && EFSYS_OPT_MCDI */