summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatt Derksen <mderkse1@us.ibm.com>2017-12-15 15:45:24 -0600
committerWilliam G. Hoffa <wghoffa@us.ibm.com>2017-12-22 09:49:35 -0500
commitd2b876356f5441e7be94c434952c25826e929370 (patch)
tree50cbf1b464584d992850c5fca5dc5e1ea6f94e87 /src
parent024dc9b9a20380fd7dbdec4f20aca23ceab751ed (diff)
downloadtalos-hostboot-d2b876356f5441e7be94c434952c25826e929370.tar.gz
talos-hostboot-d2b876356f5441e7be94c434952c25826e929370.zip
Lock i2c around vpd write message to FSP at runtime
Adding this lock mechanism to handle contention between the Host and OCC. Using the Host's lock as a proxy for any operations we want the FSP to do for us. HBRT will now call to lock the master i2c, then call down to the FSP to do the VPD write, then call to unlock the master. Change-Id: Ifa06b3bf12fe9914980d39d2663f032ddb950b94 RTC:184131 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/51041 Reviewed-by: Martin Gloff <mgloff@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: William G. Hoffa <wghoffa@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/runtime/interface.h16
-rw-r--r--src/include/usr/vpd/vpdreasoncodes.H6
-rw-r--r--src/usr/util/runtime/rt_fwreq_helper.C47
-rw-r--r--src/usr/vpd/runtime/rt_vpd.C246
4 files changed, 310 insertions, 5 deletions
diff --git a/src/include/runtime/interface.h b/src/include/runtime/interface.h
index 3a6ac6b93..b2c7312a4 100644
--- a/src/include/runtime/interface.h
+++ b/src/include/runtime/interface.h
@@ -74,6 +74,7 @@ enum MemoryError_t
MEMORY_ERROR_PREDICTIVE = 2,
};
+
/**
* I2C Master Description: chip, engine and port packed into
* a single 64-bit argument
@@ -504,7 +505,6 @@ typedef struct hostInterfaces
/**
* @brief Structure to be sent and received in the
* firmware_request call
- *
*/
enum
{
@@ -515,6 +515,7 @@ typedef struct hostInterfaces
HBRT_FW_MSG_HBRT_FSP_REQ = 4,
HBRT_FW_MSG_TYPE_ERROR_LOG = 5,
HBRT_FW_MSG_HBRT_FSP_RESP = 6,
+ HBRT_FW_MSG_TYPE_I2C_LOCK = 7,
};
struct hbrt_fw_msg // define struct hbrt_fw_msg
@@ -558,6 +559,19 @@ typedef struct hostInterfaces
// (uint8_t*)&l_req_fw_msg->error_log.i_data;
} __attribute__ ((packed)) error_log;
+
+ // This struct is sent from HBRT with
+ // io_type set to HBRT_FW_MSG_TYPE_I2C_LOCK
+ struct
+ {
+ uint64_t i_chipId; // processor chip ID plus ID type,
+ // always proc (0x0)
+ uint8_t i_i2cMaster; // i2c master
+ // B=0, C=1, D=2, E=3
+ uint8_t i_operation; // type of operation to perform
+ // 1 = lock, 2 = unlock
+ } __attribute__ ((packed)) req_i2c_lock;
+
// This struct is sent from HBRT with
// io_type set to HBRT_FW_MSG_HBRT_FSP_REQ or
// HBRT_FW_MSG_HBRT_FSP_RESP
diff --git a/src/include/usr/vpd/vpdreasoncodes.H b/src/include/usr/vpd/vpdreasoncodes.H
index a9c62aca5..282bed144 100644
--- a/src/include/usr/vpd/vpdreasoncodes.H
+++ b/src/include/usr/vpd/vpdreasoncodes.H
@@ -93,6 +93,9 @@ enum vpdModuleId
VPD_BLD_RT_IMAGE = 0x82,
VPD_SEND_MBOX_WRITE_MESSAGE = 0x83,
VPD_MOD_XXX = 0x84,
+ VPD_SEND_I2C_LOCK_MSG = 0x85,
+ VPD_FILL_I2C_LOCK_MSG = 0x86,
+
};
/**
@@ -141,6 +144,9 @@ enum vpdReasonCode
VPD_INVALID_LENGTH = VPD_COMP_ID | 0x36,
VPD_RT_NULL_FIRMWARE_REQUEST_PTR = VPD_COMP_ID | 0x37,
VPD_RC_XXX = VPD_COMP_ID | 0x38,
+ VPD_TARGET_CHIP_NOT_FOUND = VPD_COMP_ID | 0x39,
+ VPD_EEPROM_VPD_PRIMARY_INFO_MISSING = VPD_COMP_ID | 0x3a,
+
};
diff --git a/src/usr/util/runtime/rt_fwreq_helper.C b/src/usr/util/runtime/rt_fwreq_helper.C
index 16c9de777..e4cf371d3 100644
--- a/src/usr/util/runtime/rt_fwreq_helper.C
+++ b/src/usr/util/runtime/rt_fwreq_helper.C
@@ -172,6 +172,24 @@ errlHndl_t firmware_request_helper(uint64_t i_reqLen, void *i_req,
}
break; // END case hostInterfaces::HBRT_FW_MSG_HBRT_FSP_REQ:
+ case hostInterfaces::HBRT_FW_MSG_TYPE_I2C_LOCK:
+ {
+ TRACFCOMP(g_trac_runtime,
+ ERR_MRK"FSP is doing a reset/reload, "
+ "sending lock msg to FSP failed. "
+ "retry:%d/%d, rc:%d",
+ i,
+ HBRT_FW_REQUEST_RETRIES,
+ rc);
+
+ l_userData1 = TWO_UINT32_TO_UINT64( rc,
+ TWO_UINT8_TO_UINT16(
+ l_req_fw_msg->req_i2c_lock.i_i2cMaster,
+ l_req_fw_msg->req_i2c_lock.i_operation) );
+ l_userData2 = l_req_fw_msg->req_i2c_lock.i_chipId;
+ }
+ break; // END case hostInterfaces::HBRT_FW_MSG_TYPE_I2C_LOCK:
+
default:
break;
} // END switch (l_req_fw_msg->io_type)
@@ -185,9 +203,11 @@ errlHndl_t firmware_request_helper(uint64_t i_reqLen, void *i_req,
* @reasoncode RC_FW_REQUEST_RESET_RELOAD_ERR
* @userdata1[0:31] Hypervisor return code
* @userdata1[32:63] Firmware Request type (HCODE Update) ||
- sequence number (FSP MSG)
+ sequence number (FSP MSG) ||
+ i2cMaster & lock operation
* @userdata2[0:31] SCOM address (HCODE Update) ||
- MBOX message type (FSP MSG)
+ MBOX message type (FSP MSG) ||
+ chipID
* @userdata2[32:63] SCOM data (HCODE Update) ||
Message Type (FSP MSG)
* @devdesc The Firmware Request call failed
@@ -313,6 +333,23 @@ errlHndl_t firmware_request_helper(uint64_t i_reqLen, void *i_req,
}
break; // END case hostInterfaces::HBRT_FW_MSG_HBRT_FSP_REQ:
+ case hostInterfaces::HBRT_FW_MSG_TYPE_I2C_LOCK:
+ {
+ TRACFCOMP(g_trac_runtime, ERR_MRK"Failed sending FSP i2c "
+ "lock message rc 0x%X; i_chipId: 0x%llX, "
+ "i_i2cMaster: %d, i_operation: %d",
+ rc,
+ l_req_fw_msg->req_i2c_lock.i_chipId,
+ l_req_fw_msg->req_i2c_lock.i_i2cMaster,
+ l_req_fw_msg->req_i2c_lock.i_operation );
+
+ l_userData1 = TWO_UINT32_TO_UINT64( rc,
+ TWO_UINT8_TO_UINT16(
+ l_req_fw_msg->req_i2c_lock.i_i2cMaster,
+ l_req_fw_msg->req_i2c_lock.i_operation) );
+ l_userData2 = l_req_fw_msg->req_i2c_lock.i_chipId;
+ }
+ break; // END case hostInterfaces::HBRT_FW_MSG_TYPE_I2C_LOCK:
default:
break;
} // END switch (l_req_fw_msg->io_type)
@@ -326,9 +363,11 @@ errlHndl_t firmware_request_helper(uint64_t i_reqLen, void *i_req,
* @reasoncode RC_FW_REQUEST_ERR
* @userdata1[0:31] Hypervisor return code
* @userdata1[32:63] Firmware Request type (HCODE Update) ||
- sequence number (FSP MSG)
+ sequence number (FSP MSG) ||
+ i2cMaster & lock operation
* @userdata2[0:31] SCOM address (HCODE Update) ||
- MBOX message type (FSP MSG)
+ MBOX message type (FSP MSG) ||
+ chipId
* @userdata2[32:63] SCOM data (HCODE Update) ||
Message Type (FSP MSG)
* @devdesc The Firmware Request call failed
diff --git a/src/usr/vpd/runtime/rt_vpd.C b/src/usr/vpd/runtime/rt_vpd.C
index fc60ece9c..216a8d8c7 100644
--- a/src/usr/vpd/runtime/rt_vpd.C
+++ b/src/usr/vpd/runtime/rt_vpd.C
@@ -35,6 +35,7 @@
#include <util/runtime/rt_fwreq_helper.H> // firmware_request_helper
#include <targeting/common/util.H>
#include <util/runtime/util_rt.H>
+#include <runtime/rt_targeting.H>
#include <runtime/interface.h>
#include <initservice/initserviceif.H>
@@ -59,6 +60,10 @@ extern trace_desc_t* g_trac_vpd;
// function once as memory is allocated with every call.
static uint64_t g_reserved_mem_addr = 0;
+// See i_operation of req_i2c_lock structure
+static const uint8_t LOCKOP_LOCK = 1;
+static const uint8_t LOCKOP_UNLOCK = 2;
+
namespace VPD
{
@@ -372,6 +377,216 @@ errlHndl_t writePNOR ( uint64_t i_byteAddr,
return err;
}
+
+/**
+ * @brief Fill in the iic lock message to send to FSP
+ * @param[in] i_target target device
+ * @param[in] i_operation 1=lock, 2=unlock
+ * @param[in/out] io_i2cLockMsg - i2c lock msg (fills this in)
+ * @platform FSP
+ * @return errlHndl_t - NULL if successful,
+ * otherwise a pointer to the error log.
+ */
+errlHndl_t fillI2CLockMsg( TARGETING::Target * i_target, uint8_t i_operation,
+ hostInterfaces::hbrt_fw_msg * io_i2cLockMsg)
+{
+ errlHndl_t l_err = nullptr;
+ TRACFCOMP( g_trac_vpd, ENTER_MRK
+ "fillI2CLockMsg: %s i2cMaster of target huid 0x%llX",
+ (i_operation == LOCKOP_LOCK)?"lock":"unlock", get_huid(i_target) );
+
+ do {
+ io_i2cLockMsg->req_i2c_lock.i_operation = i_operation;
+
+ // find i2cMaster
+ TARGETING::EepromVpdPrimaryInfo l_eepromData;
+ // Using tryGetAttr as we want the code to continue
+ if(! (i_target->tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO>
+ ( l_eepromData )) )
+ {
+ TRACFCOMP( g_trac_vpd, ERR_MRK"fillI2CLockMsg() - "
+ "unable to get ATTR_EEPROM_VPD_PRIMARY_INFO from 0x%llX",
+ TARGETING::get_huid(i_target) );
+
+ /*@
+ * @errortype
+ * @severity ERRORLOG::ERRL_SEV_PREDICTIVE
+ * @moduleid VPD::VPD_FILL_I2C_LOCK_MSG
+ * @reasoncode VPD::VPD_EEPROM_VPD_PRIMARY_INFO_MISSING
+ * @userdata1 HUID of target
+ * @userdata2 nothing
+ * @devdesc Unable to find VPD info necessary
+ * for lock/unlock() request
+ * @custdesc A problem was detected during runtime of
+ * the system while updating VPD
+ */
+ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_PREDICTIVE,
+ VPD::VPD_FILL_I2C_LOCK_MSG,
+ VPD::VPD_EEPROM_VPD_PRIMARY_INFO_MISSING,
+ TARGETING::get_huid(i_target),
+ 0, true );
+ break;
+ }
+
+
+ io_i2cLockMsg->req_i2c_lock.i_i2cMaster = l_eepromData.engine;
+
+ // Since it exists, convert to a target
+ TARGETING::Target * l_pChipTarget =
+ TARGETING::targetService().toTarget(l_eepromData.i2cMasterPath);
+
+ if( nullptr == l_pChipTarget )
+ {
+ TRACFCOMP( g_trac_vpd,
+ ERR_MRK"fillI2CLockMsg() - I2C Master "
+ "Path target was NULL!" );
+
+ /*@
+ * @errortype
+ * @severity ERRORLOG::ERRL_SEV_PREDICTIVE
+ * @moduleid VPD::VPD_FILL_I2C_LOCK_MSG
+ * @reasoncode VPD::VPD_TARGET_CHIP_NOT_FOUND
+ * @userdata1 HUID of target
+ * @userdata2 Nothing
+ * @devdesc Unable to find chipId for lock/unlock() request
+ * @custdesc A problem was detected during runtime of
+ * the system where locking is currently
+ * unavailable for sending vpd to the host
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_PREDICTIVE,
+ VPD::VPD_FILL_I2C_LOCK_MSG,
+ VPD::VPD_TARGET_CHIP_NOT_FOUND,
+ TARGETING::get_huid(i_target),
+ 0,true);
+ break;
+ }
+
+ // Get the Proc Chip Id
+ RT_TARG::rtChipId_t l_chipId = 0;
+ l_err = RT_TARG::getRtTarget(l_pChipTarget, l_chipId);
+ if(l_err)
+ {
+ TRACFCOMP( g_trac_vpd, ERR_MRK"fillI2CLockMsg: getRtTarget ERROR" );
+ break;
+ }
+ io_i2cLockMsg->req_i2c_lock.i_chipId =
+ reinterpret_cast<uint64_t>(l_chipId);
+ }
+ while (0);
+
+ TRACFCOMP( g_trac_vpd, EXIT_MRK
+ "fillI2CLockMsg: target 0x%llX %s message "
+ "i_chipId: 0x%llX, i_i2cMaster: %d, i_operation: %d",
+ get_huid(i_target), (i_operation == LOCKOP_LOCK)?"lock":"unlock",
+ io_i2cLockMsg->req_i2c_lock.i_chipId,
+ io_i2cLockMsg->req_i2c_lock.i_i2cMaster,
+ io_i2cLockMsg->req_i2c_lock.i_operation );
+
+ return l_err;
+}
+
+/**
+ * @brief Send iic lock message to FSP
+ * @param[in] i_target target device
+ * @param[in] i_operation 1=lock, 2=unlock
+ * @platform FSP
+ * @return errlHndl_t - nullptr if successful,
+ * otherwise a pointer to the error log.
+ */
+errlHndl_t sendI2CLockMsg( TARGETING::Target * i_target,
+ uint8_t i_operation )
+{
+ errlHndl_t l_err = nullptr;
+
+ TRACFCOMP( g_trac_vpd, INFO_MRK
+ "sendI2CLockMsg: %s i2cMaster of target huid 0x%llX",
+ (i_operation == LOCKOP_LOCK)?"lock":"unlock", get_huid(i_target) );
+
+ hostInterfaces::hbrt_fw_msg *l_req_fw_msg = nullptr;
+ hostInterfaces::hbrt_fw_msg *l_resp_fw_msg = nullptr;
+
+ do
+ {
+ if ((nullptr == g_hostInterfaces) ||
+ (nullptr == g_hostInterfaces->firmware_request))
+ {
+ /*@
+ * @errortype
+ * @severity ERRORLOG::ERRL_SEV_INFORMATIONAL
+ * @moduleid VPD::VPD_SEND_I2C_LOCK_MSG
+ * @reasoncode VPD::VPD_RT_NULL_FIRMWARE_REQUEST_PTR
+ * @userdata1 HUID of target
+ * @userdata2 I2C Lock message type
+ * @devdesc MBOX send not supported in HBRT
+ * @custdesc A problem was detected during runtime of
+ * the system where locking is currently
+ * unavailable for sending vpd to the host
+ */
+ l_err= new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_INFORMATIONAL,
+ VPD::VPD_SEND_I2C_LOCK_MSG,
+ VPD::VPD_RT_NULL_FIRMWARE_REQUEST_PTR,
+ TARGETING::get_huid(i_target),
+ hostInterfaces::HBRT_FW_MSG_TYPE_I2C_LOCK,
+ true);
+ break;
+ }
+
+ // Get an accurate size of memory actually needed to transport the data
+ size_t l_req_fw_msg_size = hostInterfaces::HBRT_FW_MSG_BASE_SIZE +
+ sizeof(hostInterfaces::hbrt_fw_msg::req_i2c_lock);
+
+ //create the firmware_request structure to carry the i2c lock msg data
+ l_req_fw_msg =
+ (hostInterfaces::hbrt_fw_msg *)malloc(l_req_fw_msg_size);
+ memset(l_req_fw_msg, 0, l_req_fw_msg_size);
+
+ // populate the firmware_request structure with given data
+ l_req_fw_msg->io_type = hostInterfaces::HBRT_FW_MSG_TYPE_I2C_LOCK;
+
+ // build up msg
+ l_err = fillI2CLockMsg(i_target, i_operation, l_req_fw_msg);
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_vpd, ERR_MRK"sendI2CLockMsg: "
+ "unable to fill in i2c %s msg",
+ (i_operation==LOCKOP_LOCK)?"lock":"unlock");
+ break;
+ }
+
+ // Create the firmware_request response struct to receive data
+ uint64_t l_resp_fw_msg_size = l_req_fw_msg_size;
+ l_resp_fw_msg =
+ (hostInterfaces::hbrt_fw_msg *)malloc(l_resp_fw_msg_size);
+ memset(l_resp_fw_msg, 0, l_resp_fw_msg_size);
+
+ // Trace out the request structure
+ TRACFBIN( g_trac_vpd, INFO_MRK"sendI2CLockMsg: "
+ "Sending firmware_request",
+ l_req_fw_msg,
+ l_req_fw_msg_size);
+
+ // Make the firmware_request call
+ l_err = firmware_request_helper(l_req_fw_msg_size,
+ l_req_fw_msg,
+ &l_resp_fw_msg_size,
+ l_resp_fw_msg);
+ }
+ while (0);
+
+ // release the memory created
+ free(l_req_fw_msg);
+ free(l_resp_fw_msg);
+ l_req_fw_msg = l_resp_fw_msg = nullptr;
+
+ // add VPD traces to all error logs
+ if (l_err)
+ {
+ l_err->collectTrace( "VPD", 256);
+ }
+
+ return l_err;
+}
+
// ------------------------------------------------------------------
// sendMboxWriteMsg
// ------------------------------------------------------------------
@@ -382,6 +597,7 @@ errlHndl_t sendMboxWriteMsg ( size_t i_numBytes,
VpdWriteMsg_t& i_record )
{
errlHndl_t l_err = nullptr;
+ errlHndl_t l_lock_errl = nullptr;
// Put the handle to the firmware messages out here
// so it is easier to free later
@@ -428,6 +644,11 @@ errlHndl_t sendMboxWriteMsg ( size_t i_numBytes,
break;
}
+ // Lock the I2C master for this target before sending VPD to
+ // prevent collisions
+ l_lock_errl = sendI2CLockMsg(i_target, LOCKOP_LOCK );
+
+
// Get an accurate size of memory needed to transport
// the data for the firmware_request request struct
uint32_t l_fsp_req_size = GENERIC_FSP_MBOX_MESSAGE_BASE_SIZE;
@@ -509,6 +730,31 @@ errlHndl_t sendMboxWriteMsg ( size_t i_numBytes,
if( l_resp_fw_msg ) { free(l_resp_fw_msg); }
l_req_fw_msg = l_resp_fw_msg = nullptr;
+ // Commit previous lock error (if any)
+ if (l_lock_errl)
+ {
+ // Associate lock error with this error
+ if (l_err)
+ {
+ l_lock_errl->plid(l_err->plid());
+ }
+ l_lock_errl->setSev(ERRORLOG::ERRL_SEV_PREDICTIVE);
+ errlCommit( l_lock_errl, VPD_COMP_ID );
+ }
+
+ // Unlock i2cMaster for this target
+ l_lock_errl = sendI2CLockMsg( i_target, LOCKOP_UNLOCK );
+ if (l_lock_errl)
+ {
+ // Associate unlock error with this error
+ if (l_err)
+ {
+ l_lock_errl->plid(l_err->plid());
+ }
+ l_lock_errl->setSev(ERRORLOG::ERRL_SEV_PREDICTIVE);
+ errlCommit( l_lock_errl, VPD_COMP_ID );
+ }
+
if (l_err)
{
// @fixme-RTC:180490 - Temporarily commit until FSP code is implemented
OpenPOWER on IntegriCloud