From 98f62f12bb16fb1039196a85a530df618f16b9e5 Mon Sep 17 00:00:00 2001 From: arybchik Date: Fri, 6 Jan 2017 07:32:19 +0000 Subject: [PATCH] MFC r310813 sfxge(4): add per-command timeout reporting to the common code In newer firmware that supports multithreaded MCDI processing, longer running commands may be run ina background thread. Add support for drivers to query the appropriate timeout for each MCDI request. Submitted by: Andy Moreton Sponsored by: Solarflare Communications, Inc. git-svn-id: svn://svn.freebsd.org/base/stable/10@311496 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/sfxge/common/ef10_impl.h | 6 +++++ sys/dev/sfxge/common/ef10_mcdi.c | 40 +++++++++++++++++++++++++++++++ sys/dev/sfxge/common/efx.h | 6 +++++ sys/dev/sfxge/common/efx_impl.h | 5 +++- sys/dev/sfxge/common/efx_mcdi.c | 13 ++++++++++ sys/dev/sfxge/common/siena_impl.h | 6 +++++ sys/dev/sfxge/common/siena_mcdi.c | 15 ++++++++++++ 7 files changed, 90 insertions(+), 1 deletion(-) diff --git a/sys/dev/sfxge/common/ef10_impl.h b/sys/dev/sfxge/common/ef10_impl.h index 913d83983..82d7f2f6f 100644 --- a/sys/dev/sfxge/common/ef10_impl.h +++ b/sys/dev/sfxge/common/ef10_impl.h @@ -330,6 +330,12 @@ ef10_mcdi_feature_supported( __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 */ diff --git a/sys/dev/sfxge/common/ef10_mcdi.c b/sys/dev/sfxge/common/ef10_mcdi.c index 46ea572c0..33591bf49 100644 --- a/sys/dev/sfxge/common/ef10_mcdi.c +++ b/sys/dev/sfxge/common/ef10_mcdi.c @@ -108,6 +108,46 @@ ef10_mcdi_fini( 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, diff --git a/sys/dev/sfxge/common/efx.h b/sys/dev/sfxge/common/efx.h index 28bc5bfce..9b65972fe 100644 --- a/sys/dev/sfxge/common/efx.h +++ b/sys/dev/sfxge/common/efx.h @@ -242,6 +242,12 @@ efx_mcdi_reboot( efx_mcdi_new_epoch( __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, diff --git a/sys/dev/sfxge/common/efx_impl.h b/sys/dev/sfxge/common/efx_impl.h index 216f6e376..c63f962cd 100644 --- a/sys/dev/sfxge/common/efx_impl.h +++ b/sys/dev/sfxge/common/efx_impl.h @@ -428,7 +428,10 @@ typedef struct efx_mcdi_ops_s { 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 { diff --git a/sys/dev/sfxge/common/efx_mcdi.c b/sys/dev/sfxge/common/efx_mcdi.c index 2c1799548..e4a918a25 100644 --- a/sys/dev/sfxge/common/efx_mcdi.c +++ b/sys/dev/sfxge/common/efx_mcdi.c @@ -67,6 +67,7 @@ static const efx_mcdi_ops_t __efx_mcdi_siena_ops = { 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 @@ static const efx_mcdi_ops_t __efx_mcdi_ef10_ops = { 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 @@ efx_mcdi_request_abort( 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) diff --git a/sys/dev/sfxge/common/siena_impl.h b/sys/dev/sfxge/common/siena_impl.h index 26e44784a..9458dca70 100644 --- a/sys/dev/sfxge/common/siena_impl.h +++ b/sys/dev/sfxge/common/siena_impl.h @@ -127,6 +127,12 @@ siena_mcdi_feature_supported( __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 diff --git a/sys/dev/sfxge/common/siena_mcdi.c b/sys/dev/sfxge/common/siena_mcdi.c index 90db28ac0..a615f88c1 100644 --- a/sys/dev/sfxge/common/siena_mcdi.c +++ b/sys/dev/sfxge/common/siena_mcdi.c @@ -247,4 +247,19 @@ siena_mcdi_feature_supported( 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 */ -- 2.45.0