From a911c8a49df0a750838050aa139918c9b786ee03 Mon Sep 17 00:00:00 2001 From: Louis Stermole Date: Mon, 8 Jul 2019 10:19:55 -0400 Subject: Fix polling timeouts for exp_omi_train and exp_check_for_ready Change-Id: Ifb260bb167dc254405884b12bf55246826d6b3bb Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/80152 Tested-by: FSP CI Jenkins Reviewed-by: STEPHEN GLANCY Reviewed-by: Mark Pizzutillo Tested-by: Jenkins Server Tested-by: PPE CI Tested-by: Hostboot CI Reviewed-by: RYAN P. KING Reviewed-by: Louis Stermole Dev-Ready: Louis Stermole Reviewed-by: Jennifer A Stofer Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/80174 Tested-by: Jenkins OP Build CI Tested-by: Jenkins OP HW Reviewed-by: Daniel M Crowell --- .../procedures/hwp/memory/lib/i2c/exp_i2c.H | 182 +++++++++++++++------ .../procedures/hwp/memory/lib/shared/exp_consts.H | 34 +++- 2 files changed, 156 insertions(+), 60 deletions(-) (limited to 'src/import/chips/ocmb') diff --git a/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H b/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H index 18bc4b808..c4acf2ced 100644 --- a/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H +++ b/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H @@ -60,6 +60,7 @@ namespace check /// @param[in] i_cmd_id the command ID /// @param[in] i_data data to check from EXP_FW_STATUS /// @param[out] o_busy true if explorer returns FW_BUSY status, false otherwise +/// @return FAPI2_RC_SUCCESS iff okay /// inline fapi2::ReturnCode status_code( const fapi2::Target& i_target, const uint8_t i_cmd_id, @@ -96,33 +97,6 @@ fapi_try_exit: return fapi2::current_err; } -/// -/// @brief Checks the I2c explorer boot stage for FUNTIME_FW -/// @param[in] i_target the OCMB target -/// @param[in] i_data data to check from EXP_FW_STATUS -/// -inline fapi2::ReturnCode runtime_boot_stage( const fapi2::Target& i_target, - const std::vector& i_data ) -{ - constexpr uint8_t EXPECTED_BOOT_STAGE = boot_stages::RUNTIME_FW; - uint8_t l_boot_stage = 0; - FAPI_TRY( status::get_boot_stage(i_target, i_data, l_boot_stage) ); - - // Check that Explorer is in the RUNTIME_FW boot stage - FAPI_ASSERT( (l_boot_stage == EXPECTED_BOOT_STAGE), - fapi2::MSS_EXP_I2C_WRONG_BOOT_STAGE(). - set_TARGET(i_target). - set_BOOT_STAGE(l_boot_stage). - set_EXPECTED_BOOT_STAGE(EXPECTED_BOOT_STAGE), - "FW_STATUS command returned wrong boot stage (0x%01x, expected 0x%01x) for %s", - l_boot_stage, EXPECTED_BOOT_STAGE, mss::c_str(i_target) ); - - return fapi2::FAPI2_RC_SUCCESS; - -fapi_try_exit: - return fapi2::current_err; -} - }// check /// @@ -138,9 +112,20 @@ inline void fw_status_setup(size_t& o_size, o_cmd_id.push_back(FW_STATUS); } +/// +/// @brief EXP_FW_BYPASS_4SEC_TIMEOUT setup helper function +/// @param[out] o_cmd_id the explorer command ID +/// +inline void fw_bypass_download_window_setup(std::vector& o_cmd_id) +{ + o_cmd_id.clear(); + o_cmd_id.push_back(FW_BYPASS_4SEC_TIMEOUT); +} + /// /// @brief get EXP_FW_STATUS bytes /// @param[in] i_target the OCMB target +/// @param[out] o_data the return data from FW_STATUS command /// @return FAPI2_RC_SUCCESS iff okay /// inline fapi2::ReturnCode get_fw_status(const fapi2::Target& i_target, @@ -159,38 +144,74 @@ fapi_try_exit: return fapi2::current_err; } +/// +/// @brief Helper function to check FW_STATUS loop termination, for unit testing +/// @param[in] i_target the OCMB target +/// @param[in] i_busy busy flag from check::status_code +/// @param[in] i_boot_stage boot_stage output from status::get_boot_stage +/// @return true if we should break out of the loop, false otherwise +/// +inline bool fw_status_loop_done(const fapi2::Target& i_target, + const bool i_busy, + const uint8_t i_boot_stage) +{ + constexpr uint8_t EXPECTED_BOOT_STAGE = boot_stages::RUNTIME_FW; + + if (i_busy) + { + FAPI_DBG( "%s reutrned FW_BUSY status. Retrying...", mss::c_str(i_target) ); + return false; + } + + if (i_boot_stage != EXPECTED_BOOT_STAGE) + { + FAPI_DBG( "%s reutrned non-RUNTIME boot stage (0x%02x). Retrying...", + mss::c_str(i_target), i_boot_stage ); + return false; + } + + return true; +} + /// /// @brief EXP_FW_STATUS /// @param[in] i_target the OCMB target +/// @param[in] i_delay delay between polls +/// @param[in] i_loops number of polling loops to perform /// @return FAPI2_RC_SUCCESS iff okay /// -inline fapi2::ReturnCode fw_status(const fapi2::Target& i_target) +inline fapi2::ReturnCode fw_status(const fapi2::Target& i_target, + const uint64_t i_delay, + const uint64_t i_loops) { - constexpr uint64_t NUM_LOOPS = 50; + constexpr uint8_t EXPECTED_BOOT_STAGE = boot_stages::RUNTIME_FW; + // So, why aren't we using the memory team's polling API? // This is a base function that will be utilized by the platform code // As such, we don't want to pull in more libraries than we need to: it would cause extra dependencies // So, we're decomposing the polling library below + fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS; bool l_busy = true; + uint8_t l_boot_stage = 0; uint64_t l_loop = 0; - // Loop until we max our our loop count or get a doorbell response - for(; l_loop < NUM_LOOPS && l_busy; ++l_loop) + // Loop until we max our our loop count or get a non-busy response + for(; l_loop < i_loops; ++l_loop) { std::vector l_data; FAPI_TRY( get_fw_status(i_target, l_data) ); FAPI_TRY( check::status_code(i_target, FW_STATUS, l_data, l_busy) ); - FAPI_TRY( check::runtime_boot_stage(i_target, l_data) ); + FAPI_TRY( status::get_boot_stage(i_target, l_data, l_boot_stage) ); - if (l_busy) + if (fw_status_loop_done(i_target, l_busy, l_boot_stage)) { - FAPI_INF( "%s reutrned FW_BUSY status. Retrying...", mss::c_str(i_target) ); - FAPI_TRY( fapi2::delay( DELAY_100NS, 200) ); + break; } + + FAPI_TRY( fapi2::delay( i_delay, 200) ); } - FAPI_DBG("%s stopped on loop%u/%u. %s", - mss::c_str(i_target), l_loop, NUM_LOOPS, (l_busy ? "FW_BUSY" : "SUCCESS")); + FAPI_DBG("%s stopped on loop %u/%u", mss::c_str(i_target), l_loop, i_loops); // Check that Explorer is not still in FW_BUSY state FAPI_ASSERT( !l_busy, @@ -199,6 +220,15 @@ inline fapi2::ReturnCode fw_status(const fapi2::Target l_configured_data(i_data); boot_config_setup(l_configured_data); - // Get data and check for errors + // Send the command FAPI_TRY(fapi2::putI2c(i_target, l_configured_data)); - FAPI_TRY(fw_status(i_target)); + + // Wait a bit for the command (DLL lock and OMI training) to complete + // Value based on initial Explorer hardware. + // The command takes ~300ms and we poll for around 100ms, so wait 250ms here + FAPI_TRY( fapi2::delay( (mss::DELAY_1MS * 250), 200) ); + + // Poll for status response + // Note: the EXP_FW_BOOT_CONFIG command trains the OMI, which takes a + // significant amount of time. We're waiting 1ms between polls, and poll for 100 loops, + // which totals at least 100ms + FAPI_TRY(fw_status(i_target, DELAY_1MS, 100)); fapi_try_exit: return fapi2::current_err; @@ -260,23 +300,40 @@ inline fapi2::ReturnCode is_ready(const fapi2::Target l_cmd_id; fw_status_setup(l_size, l_cmd_id); - // We just ignore the data. We'll see FAPI2_RC_SUCCESS if - // the I2C returns an ACK. + // We'll see FAPI2_RC_SUCCESS if the I2C returns an ACK. + // We just ignore the data std::vector l_data; return fapi2::getI2c(i_target, l_size, l_cmd_id, l_data); } +/// +/// @brief EXP_FW_BYPASS_4SEC_TIMEOUT +/// @param[in] i_target the OCMB target +/// @return FAPI2_RC_SUCCESS iff okay +/// +inline fapi2::ReturnCode fw_bypass_download_window(const fapi2::Target& i_target) +{ + std::vector l_cmd_id; + fw_bypass_download_window_setup(l_cmd_id); + + // We'll see FAPI2_RC_SUCCESS if the I2C returns an ACK. + return fapi2::putI2c(i_target, l_cmd_id); +} + /// /// @brief Helper function for exp_check_for_ready /// @param[in] i_target the controller -/// @param[in] i_poll_count the number of times to run the fw_status command (default = 50) -/// @param[in] i_delay delay in ns between fw_status command attempts (default = 200ns) +/// @param[in] i_poll_count the number of times to run the fw_status command (default = 200) +/// @param[in] i_delay delay in ns between fw_status command attempts (default = 1ms) /// @return FAPI2_RC_SUCCESS iff ok /// inline fapi2::ReturnCode exp_check_for_ready_helper(const fapi2::Target& i_target, - const uint64_t i_poll_count = DEFAULT_POLL_LIMIT, - const uint64_t i_delay = 200) + const uint64_t i_poll_count = 200, + const uint64_t i_delay = DELAY_1MS) { + std::vector l_data; + uint8_t l_boot_stage = 0; + // Using using default parameters from class, with overrides for delay and poll_count mss::poll_parameters l_poll_params(DELAY_10NS, 200, @@ -296,16 +353,37 @@ inline fapi2::ReturnCode exp_check_for_ready_helper(const fapi2::Targetbool { - return mss::exp::i2c::fw_status(i_target) == fapi2::FAPI2_RC_SUCCESS; + return mss::exp::i2c::is_ready(i_target) == fapi2::FAPI2_RC_SUCCESS; }), - fapi2::MSS_EXP_STATUS_POLLING_TIMEOUT(). + fapi2::MSS_EXP_I2C_POLLING_TIMEOUT(). set_TARGET(i_target), - "Failed to see a successful return code -- polling timeout on %s", + "Failed to see an ACK from I2C -- polling timeout on %s", mss::c_str(i_target) ); + // Now poll the EXP_FW_STATUS command until it returns SUCCESS and RUNTIME_FW + FAPI_TRY(fw_status(i_target, i_delay, i_poll_count)); + return fapi2::FAPI2_RC_SUCCESS; fapi_try_exit: @@ -352,7 +430,7 @@ inline fapi2::ReturnCode fw_reg_write(const fapi2::Target