Skip to content

Commit

Permalink
Fix polling timeouts for exp_omi_train and exp_check_for_ready
Browse files Browse the repository at this point in the history
Change-Id: Ifb260bb167dc254405884b12bf55246826d6b3bb
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/80152
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com>
Reviewed-by: Mark Pizzutillo <mark.pizzutillo@ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: PPE CI <ppe-ci+hostboot@us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com>
Reviewed-by: RYAN P. KING <rpking@us.ibm.com>
Reviewed-by: Louis Stermole <stermole@us.ibm.com>
Dev-Ready: Louis Stermole <stermole@us.ibm.com>
Reviewed-by: Jennifer A Stofer <stofer@us.ibm.com>
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/80173
Reviewed-by: RAJA DAS <rajadas2@in.ibm.com>
  • Loading branch information
stermole authored and RAJA DAS committed Jul 20, 2019
1 parent 6d59cee commit 5b8210b
Showing 1 changed file with 130 additions and 52 deletions.
182 changes: 130 additions & 52 deletions src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/i2c/exp_i2c.H
Expand Up @@ -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<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
const uint8_t i_cmd_id,
Expand Down Expand Up @@ -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<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
const std::vector<uint8_t>& 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

///
Expand All @@ -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<uint8_t>& 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<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
Expand All @@ -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<fapi2::TARGET_TYPE_OCMB_CHIP>& 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<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target)
inline fapi2::ReturnCode fw_status(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& 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<uint8_t> 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,
Expand All @@ -199,6 +220,15 @@ inline fapi2::ReturnCode fw_status(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_C
"Polling timeout on FW_STATUS command (still FW_BUSY) for %s",
mss::c_str(i_target) );

// Check that Explorer is in 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),
"Polling timeout on FW_STATUS command (wrong boot stage: 0x%01x, expected 0x%01x) for %s",
l_boot_stage, EXPECTED_BOOT_STAGE, mss::c_str(i_target) );

fapi_try_exit:
return fapi2::current_err;
}
Expand Down Expand Up @@ -239,9 +269,19 @@ inline fapi2::ReturnCode boot_config(const fapi2::Target<fapi2::TARGET_TYPE_OCMB
std::vector<uint8_t> 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;
Expand All @@ -260,23 +300,40 @@ inline fapi2::ReturnCode is_ready(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CH
std::vector<uint8_t> 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<uint8_t> 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<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target)
{
std::vector<uint8_t> 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<fapi2::TARGET_TYPE_OCMB_CHIP>& 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<uint8_t> 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,
Expand All @@ -296,16 +353,37 @@ inline fapi2::ReturnCode exp_check_for_ready_helper(const fapi2::Target<fapi2::T
"Failed to see an ACK from I2C -- polling timeout on %s",
mss::c_str(i_target) );

// We send the EXP_FW_STATUS command as a sanity check to see if it returns SUCCESS
// If we're already in RUNTIME_FW stage, due to fuse settings or running procedures manually,
// we can (and should) skip the bypass and polling here
FAPI_TRY( get_fw_status(i_target, l_data) );
FAPI_TRY( status::get_boot_stage(i_target, l_data, l_boot_stage) );

if (l_boot_stage == boot_stages::RUNTIME_FW)
{
return fapi2::FAPI2_RC_SUCCESS;
}

// MSCC explorer firmware arch spec 4.1.6.5
// Boot ROM will wait 4 secs and will proceed for normal boot operation. During this time,
// I2C channel will be disabled and Host will see NACK on the bus for subsequent EXP_FW_STATUS
// command.
// Sending FW_BYPASS_4SEC_TIMEOUT command will bypass the 4 secs
// and immediately load the runtime firmware.
FAPI_TRY(fw_bypass_download_window(i_target));

// Loop again until we get an ACK from i2c
FAPI_ASSERT( mss::poll(i_target, l_poll_params, [i_target]()->bool
{
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:
Expand Down Expand Up @@ -352,7 +430,7 @@ inline fapi2::ReturnCode fw_reg_write(const fapi2::Target<fapi2::TARGET_TYPE_OC
i_addr, mss::fapi_pos(i_target));

// Check status of operation
FAPI_TRY(fw_status(i_target),
FAPI_TRY(fw_status(i_target, DELAY_1MS, 100),
"Invalid Status after FW_REG_WRITE operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X",
i_addr, mss::fapi_pos(i_target));

Expand Down Expand Up @@ -398,7 +476,7 @@ inline fapi2::ReturnCode fw_reg_read(const fapi2::Target<fapi2::TARGET_TYPE_OCMB
i_addr, mss::fapi_pos(i_target));

// Check i2c status after operation
FAPI_TRY(fw_status(i_target),
FAPI_TRY(fw_status(i_target, DELAY_1MS, 100),
"Invalid Status after FW_REG_ADDR_LATCH operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X",
i_addr, mss::fapi_pos(i_target));

Expand Down Expand Up @@ -434,7 +512,7 @@ inline fapi2::ReturnCode fw_reg_read(const fapi2::Target<fapi2::TARGET_TYPE_OCMB
FW_REG_ADDR_LATCH_SIZE, l_tmp_vector[0] );

// Check i2c status after operation
FAPI_TRY(fw_status(i_target),
FAPI_TRY(fw_status(i_target, DELAY_1MS, 100),
"Invalid Status after FW_REG_READ operation to 0x%.8X on OCMB w/ fapiPos = 0x%.8X",
i_addr, mss::fapi_pos(i_target));

Expand Down

0 comments on commit 5b8210b

Please sign in to comment.