From 2eb08d3cae4281cd9d10fae679b3f2fd3f999d74 Mon Sep 17 00:00:00 2001 From: arybchik Date: Fri, 6 Jan 2017 07:31:15 +0000 Subject: [PATCH] MFC r310765 sfxge(4): add support for firmware-verified NVRAM updates to the common code Submitted by: Andy Moreton Sponsored by: Solarflare Communications, Inc. git-svn-id: svn://svn.freebsd.org/base/stable/10@311495 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/sfxge/common/ef10_impl.h | 4 +- sys/dev/sfxge/common/ef10_nic.c | 12 ++++ sys/dev/sfxge/common/ef10_nvram.c | 28 +++++++--- sys/dev/sfxge/common/efx.h | 4 +- sys/dev/sfxge/common/efx_impl.h | 5 +- sys/dev/sfxge/common/efx_nvram.c | 90 +++++++++++++++++++++++++----- sys/dev/sfxge/common/siena_impl.h | 4 +- sys/dev/sfxge/common/siena_nic.c | 2 + sys/dev/sfxge/common/siena_nvram.c | 24 ++++++-- 9 files changed, 140 insertions(+), 33 deletions(-) diff --git a/sys/dev/sfxge/common/ef10_impl.h b/sys/dev/sfxge/common/ef10_impl.h index 0049eeaf9..913d83983 100644 --- a/sys/dev/sfxge/common/ef10_impl.h +++ b/sys/dev/sfxge/common/ef10_impl.h @@ -384,7 +384,7 @@ ef10_nvram_partn_lock( __in efx_nic_t *enp, __in uint32_t partn); -extern void +extern __checkReturn efx_rc_t ef10_nvram_partn_unlock( __in efx_nic_t *enp, __in uint32_t partn); @@ -451,7 +451,7 @@ ef10_nvram_partn_write( __out_bcount(size) caddr_t data, __in size_t size); -extern void +extern __checkReturn efx_rc_t ef10_nvram_partn_rw_finish( __in efx_nic_t *enp, __in uint32_t partn); diff --git a/sys/dev/sfxge/common/ef10_nic.c b/sys/dev/sfxge/common/ef10_nic.c index e6e3deda4..c3067bd03 100644 --- a/sys/dev/sfxge/common/ef10_nic.c +++ b/sys/dev/sfxge/common/ef10_nic.c @@ -1105,6 +1105,18 @@ ef10_get_datapath_caps( encp->enc_mac_stats_40g_tx_size_bins = CAP_FLAG2(flags2, MAC_STATS_40G_TX_SIZE_BINS) ? B_TRUE : B_FALSE; + /* + * Check if firmware-verified NVRAM updates must be used. + * + * The firmware trusted installer requires all NVRAM updates to use + * version 2 of MC_CMD_NVRAM_UPDATE_START (to enable verified update) + * and version 2 of MC_CMD_NVRAM_UPDATE_FINISH (to verify the updated + * partition and report the result). + */ + encp->enc_fw_verified_nvram_update_required = + CAP_FLAG2(flags2, NVRAM_UPDATE_REPORT_VERIFY_RESULT) ? + B_TRUE : B_FALSE; + #undef CAP_FLAG #undef CAP_FLAG2 diff --git a/sys/dev/sfxge/common/ef10_nvram.c b/sys/dev/sfxge/common/ef10_nvram.c index d70af7823..ccedb8a62 100644 --- a/sys/dev/sfxge/common/ef10_nvram.c +++ b/sys/dev/sfxge/common/ef10_nvram.c @@ -2046,22 +2046,26 @@ ef10_nvram_partn_write( return (rc); } - void + __checkReturn efx_rc_t ef10_nvram_partn_unlock( __in efx_nic_t *enp, __in uint32_t partn) { - boolean_t reboot; + boolean_t reboot = B_FALSE; + uint32_t result = 0; /* FIXME: MC_CMD_NVRAM_VERIFY_RC_UNKNOWN */ efx_rc_t rc; - reboot = B_FALSE; - if ((rc = efx_mcdi_nvram_update_finish(enp, partn, reboot)) != 0) + rc = efx_mcdi_nvram_update_finish(enp, partn, reboot, &result); + if (rc != 0) goto fail1; - return; + return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); + + /* FIXME: log result if verified firmware update fails */ + return (rc); } __checkReturn efx_rc_t @@ -2359,12 +2363,22 @@ ef10_nvram_partn_rw_start( return (rc); } - void + __checkReturn efx_rc_t ef10_nvram_partn_rw_finish( __in efx_nic_t *enp, __in uint32_t partn) { - ef10_nvram_partn_unlock(enp, partn); + efx_rc_t rc; + + if ((rc = ef10_nvram_partn_unlock(enp, partn)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); } #endif /* EFSYS_OPT_NVRAM */ diff --git a/sys/dev/sfxge/common/efx.h b/sys/dev/sfxge/common/efx.h index ac8d500c5..28bc5bfce 100644 --- a/sys/dev/sfxge/common/efx.h +++ b/sys/dev/sfxge/common/efx.h @@ -1177,6 +1177,8 @@ typedef struct efx_nic_cfg_s { /* Minimum unidirectional bandwidth in Mb/s to max out all ports */ uint32_t enc_required_pcie_bandwidth_mbps; uint32_t enc_max_pcie_link_gen; + /* Firmware verifies integrity of NVRAM updates */ + uint32_t enc_fw_verified_nvram_update_required; } efx_nic_cfg_t; #define EFX_PCI_FUNCTION_IS_PF(_encp) ((_encp)->enc_vf == 0xffff) @@ -1360,7 +1362,7 @@ efx_nvram_rw_start( __in efx_nvram_type_t type, __out_opt size_t *pref_chunkp); -extern void +extern __checkReturn efx_rc_t efx_nvram_rw_finish( __in efx_nic_t *enp, __in efx_nvram_type_t type); diff --git a/sys/dev/sfxge/common/efx_impl.h b/sys/dev/sfxge/common/efx_impl.h index de0ef396e..216f6e376 100644 --- a/sys/dev/sfxge/common/efx_impl.h +++ b/sys/dev/sfxge/common/efx_impl.h @@ -454,7 +454,7 @@ typedef struct efx_nvram_ops_s { unsigned int, size_t); efx_rc_t (*envo_partn_write)(efx_nic_t *, uint32_t, unsigned int, caddr_t, size_t); - void (*envo_partn_rw_finish)(efx_nic_t *, uint32_t); + efx_rc_t (*envo_partn_rw_finish)(efx_nic_t *, uint32_t); efx_rc_t (*envo_partn_get_version)(efx_nic_t *, uint32_t, uint32_t *, uint16_t *); efx_rc_t (*envo_partn_set_version)(efx_nic_t *, uint32_t, @@ -542,7 +542,8 @@ efx_mcdi_nvram_write( efx_mcdi_nvram_update_finish( __in efx_nic_t *enp, __in uint32_t partn, - __in boolean_t reboot); + __in boolean_t reboot, + __out_opt uint32_t *resultp); #if EFSYS_OPT_DIAG diff --git a/sys/dev/sfxge/common/efx_nvram.c b/sys/dev/sfxge/common/efx_nvram.c index a17cd789f..60169fc31 100644 --- a/sys/dev/sfxge/common/efx_nvram.c +++ b/sys/dev/sfxge/common/efx_nvram.c @@ -362,13 +362,14 @@ efx_nvram_write_chunk( return (rc); } - void + __checkReturn efx_rc_t efx_nvram_rw_finish( __in efx_nic_t *enp, __in efx_nvram_type_t type) { const efx_nvram_ops_t *envop = enp->en_envop; uint32_t partn; + efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); @@ -378,10 +379,24 @@ efx_nvram_rw_finish( EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); - if (envop->envo_type_to_partn(enp, type, &partn) == 0) - envop->envo_partn_rw_finish(enp, partn); + if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) + goto fail1; + + if ((rc = envop->envo_partn_rw_finish(enp, partn)) != 0) + goto fail2; + + enp->en_nvram_locked = EFX_NVRAM_INVALID; + + return (0); +fail2: + EFSYS_PROBE(fail2); enp->en_nvram_locked = EFX_NVRAM_INVALID; + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); } __checkReturn efx_rc_t @@ -696,12 +711,16 @@ efx_mcdi_nvram_info( return (rc); } +/* + * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified + * NVRAM updates. Older firmware will ignore the flags field in the request. + */ __checkReturn efx_rc_t efx_mcdi_nvram_update_start( __in efx_nic_t *enp, __in uint32_t partn) { - uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN, + uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN, MC_CMD_NVRAM_UPDATE_START_OUT_LEN)]; efx_mcdi_req_t req; efx_rc_t rc; @@ -709,11 +728,14 @@ efx_mcdi_nvram_update_start( (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_UPDATE_START; req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN; + req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN; - MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn); + MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn); + + MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS, + NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1); efx_mcdi_execute(enp, &req); @@ -886,26 +908,37 @@ efx_mcdi_nvram_write( return (rc); } + +/* + * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified + * NVRAM updates. Older firmware will ignore the flags field in the request. + */ __checkReturn efx_rc_t efx_mcdi_nvram_update_finish( __in efx_nic_t *enp, __in uint32_t partn, - __in boolean_t reboot) + __in boolean_t reboot, + __out_opt uint32_t *resultp) { + const efx_nic_cfg_t *encp = &enp->en_nic_cfg; efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN, - MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)]; + uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN, + MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN)]; + uint32_t result = 0; /* FIXME: use MC_CMD_NVRAM_VERIFY_RC_UNKNOWN */ efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH; req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN; + req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN; req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN; + req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN; - MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn); - MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot); + MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn); + MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot); + + MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS, + NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1); efx_mcdi_execute(enp, &req); @@ -914,11 +947,42 @@ efx_mcdi_nvram_update_finish( goto fail1; } + if (encp->enc_fw_verified_nvram_update_required == B_FALSE) { + /* Report success if verified updates are not supported. */ + result = MC_CMD_NVRAM_VERIFY_RC_SUCCESS; + } else { + /* Firmware-verified NVRAM updates are required */ + if (req.emr_out_length_used < + MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + result = + MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE); + + if (result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) { + /* Mandatory verification failed */ + rc = EINVAL; + goto fail3; + } + } + + if (resultp != NULL) + *resultp = result; + return (0); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); + /* Always report verification result */ + if (resultp != NULL) + *resultp = result; + return (rc); } diff --git a/sys/dev/sfxge/common/siena_impl.h b/sys/dev/sfxge/common/siena_impl.h index bce0494de..26e44784a 100644 --- a/sys/dev/sfxge/common/siena_impl.h +++ b/sys/dev/sfxge/common/siena_impl.h @@ -136,7 +136,7 @@ siena_nvram_partn_lock( __in efx_nic_t *enp, __in uint32_t partn); -extern void +extern __checkReturn efx_rc_t siena_nvram_partn_unlock( __in efx_nic_t *enp, __in uint32_t partn); @@ -208,7 +208,7 @@ siena_nvram_partn_write( __out_bcount(size) caddr_t data, __in size_t size); -extern void +extern __checkReturn efx_rc_t siena_nvram_partn_rw_finish( __in efx_nic_t *enp, __in uint32_t partn); diff --git a/sys/dev/sfxge/common/siena_nic.c b/sys/dev/sfxge/common/siena_nic.c index 6dfc05467..331d5a5ae 100644 --- a/sys/dev/sfxge/common/siena_nic.c +++ b/sys/dev/sfxge/common/siena_nic.c @@ -166,6 +166,8 @@ siena_board_cfg( encp->enc_required_pcie_bandwidth_mbps = 2 * 10000; encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN2; + encp->enc_fw_verified_nvram_update_required = B_FALSE; + return (0); fail2: diff --git a/sys/dev/sfxge/common/siena_nvram.c b/sys/dev/sfxge/common/siena_nvram.c index de6fd01c9..762db078f 100644 --- a/sys/dev/sfxge/common/siena_nvram.c +++ b/sys/dev/sfxge/common/siena_nvram.c @@ -170,7 +170,7 @@ siena_nvram_partn_write( return (rc); } - void + __checkReturn efx_rc_t siena_nvram_partn_unlock( __in efx_nic_t *enp, __in uint32_t partn) @@ -186,14 +186,16 @@ siena_nvram_partn_unlock( partn == MC_CMD_NVRAM_TYPE_PHY_PORT1 || partn == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO); - if ((rc = efx_mcdi_nvram_update_finish(enp, partn, reboot)) != 0) { + rc = efx_mcdi_nvram_update_finish(enp, partn, reboot, NULL); + if (rc != 0) goto fail1; - } - return; + return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); } #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ @@ -585,12 +587,22 @@ siena_nvram_partn_rw_start( return (rc); } - void + __checkReturn efx_rc_t siena_nvram_partn_rw_finish( __in efx_nic_t *enp, __in uint32_t partn) { - siena_nvram_partn_unlock(enp, partn); + efx_rc_t rc; + + if ((rc = siena_nvram_partn_unlock(enp, partn)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); } __checkReturn efx_rc_t -- 2.45.0