diff options
author | Matt Derksen <mderkse1@us.ibm.com> | 2018-08-30 08:10:40 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2018-09-20 17:06:38 -0500 |
commit | 165bb46bac36d2774b7fe36543024710053ec3d0 (patch) | |
tree | f21eb63d24214397c161e76641ee6ef4c1added0 /src/usr/i2c | |
parent | 5abc57bc8352ef13ab7aa23edfbc2d607f9cd5b2 (diff) | |
download | talos-hostboot-165bb46bac36d2774b7fe36543024710053ec3d0.tar.gz talos-hostboot-165bb46bac36d2774b7fe36543024710053ec3d0.zip |
Support fapi2 i2c functions
New interface in fapi2 to perform i2c operations directly.
This is needed for OCMB access before we get OMI bus running,
specifically as part of a cmd/rsp protocol.
Change-Id: I8b778f12f8c0c6820ceb51146f1e21d30891c964
RTC:197029
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/63919
Tested-by: Jenkins Server <pfd-jenkins+hostboot@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: Christian R. Geddes <crgeddes@us.ibm.com>
Reviewed-by: Corey V. Swenson <cswenson@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/i2c')
-rw-r--r-- | src/usr/i2c/fapi_i2c_dd.C | 413 | ||||
-rw-r--r-- | src/usr/i2c/fapi_i2c_dd.H | 103 | ||||
-rw-r--r-- | src/usr/i2c/makefile | 1 |
3 files changed, 517 insertions, 0 deletions
diff --git a/src/usr/i2c/fapi_i2c_dd.C b/src/usr/i2c/fapi_i2c_dd.C new file mode 100644 index 000000000..23bf5bdbe --- /dev/null +++ b/src/usr/i2c/fapi_i2c_dd.C @@ -0,0 +1,413 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/i2c/fapi_i2c_dd.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file fapi_i2c_dd.C + * + * @brief Provides a thin layer on top of our I2C device driver to + * serve as the back-end for the FAPI i2c interfaces. + * It will locate the appropriate i2c device information + * and will perform retries as needed. + */ + +#include <trace/interface.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <errl/errludtarget.H> +#include <errl/errludstring.H> +#include <targeting/common/targetservice.H> +#include <targeting/common/commontargeting.H> +#include <devicefw/driverif.H> +#include <i2c/i2creasoncodes.H> +#include "fapi_i2c_dd.H" + +extern trace_desc_t* g_trac_i2c; + +using namespace DeviceFW; + +namespace FAPI_I2C_DD +{ + +// Easy macro replace for unit testing +//#define TRACUCOMP(args...) TRACFCOMP(args) +#define TRACUCOMP(args...) + + +// ------------------------------------------------------------------ +// errorIsRetryable +// ------------------------------------------------------------------ +static bool errorIsRetryable(uint16_t reasonCode) +{ + return reasonCode == I2C::I2C_NACK_ONLY_FOUND || + reasonCode == I2C::I2C_ARBITRATION_LOST_ONLY_FOUND; +} + +// Link to device driver interface +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::FAPI_I2C, + TARGETING::TYPE_OCMB_CHIP, + fapiI2cPerformOp ); + +errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType, + TARGETING::Target * i_target, + void * io_buffer, + size_t & io_buflen, + int64_t i_accessType, + va_list i_args) +{ + errlHndl_t l_err = nullptr; + errlHndl_t l_err_retryable = nullptr; + const uint8_t FAPI_I2C_MAX_RETRIES = 2; + + TARGETING::ATTR_FAPI_I2C_CONTROL_INFO_type l_i2cInfo; + uint8_t * l_cfgData = nullptr; + + size_t l_cfgSize = va_arg( i_args, size_t ); + if (l_cfgSize > 0) + { + l_cfgData = va_arg( i_args, uint8_t* ); + } + + TRACUCOMP(g_trac_i2c, ENTER_MRK"fapiI2cPerformOp(): " + "%s operation on target %.8X", + (i_opType==DeviceFW::READ)?"READ":"WRITE", + TARGETING::get_huid(i_target) ); + + do + { + // Grab i2c access information + l_err = readI2cAttributes (i_target, l_i2cInfo); + if( l_err ) + { + break; + } + + // grab target pointer to master + TARGETING::TargetService& ts = TARGETING::targetService(); + TARGETING::Target * i2cm = ts.toTarget(l_i2cInfo.i2cMasterPath); + + TARGETING::Target * sys = nullptr; + ts.getTopLevelTarget( sys ); + + // master target has to exist and can not be just sys target + if( (i2cm == nullptr) || (i2cm == sys) ) + { + TRACFCOMP( g_trac_i2c, ERR_MRK"fapiI2cPerformOp() - " + "I2C Master path (%s) not valid", + l_i2cInfo.i2cMasterPath.toString() ); + /*@ + * @errortype + * @reasoncode I2C::INVALID_MASTER_TARGET + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid I2C::FAPI_I2C_PERFORM_OP + * @userdata1 HUID of target with FAPI_I2C_CONTROL_INFO + * @devdesc Invalid I2C master path + * @custdesc A problem occurred during the IPL + * of the system. + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + I2C::FAPI_I2C_PERFORM_OP, + I2C::INVALID_MASTER_TARGET, + TARGETING::get_huid(i_target), + 0, + true /*Add HB SW Callout*/ ); + + l_err->collectTrace( I2C_COMP_NAME ); + break; + } + + // Verify valid operation type + if ((i_opType != DeviceFW::READ) && (i_opType != DeviceFW::WRITE)) + { + TRACFCOMP( g_trac_i2c, + ERR_MRK"fapiI2cPerformOp() - Invalid OP type %d.", + i_opType ); + /*@ + * @errortype + * @reasoncode I2C::I2C_INVALID_OP_TYPE + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid I2C::FAPI_I2C_PERFORM_OP + * @userdata1 OP type + * @userdata2 HUID of target + * @devdesc Invalid I2C device type + * @custdesc A problem occurred during the IPL + * of the system. + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + I2C::FAPI_I2C_PERFORM_OP, + I2C::I2C_INVALID_OP_TYPE, + i_opType, + TARGETING::get_huid(i_target), + true /*Add HB SW Callout*/ ); + + l_err->collectTrace( I2C_COMP_NAME ); + break; + } + + //////////////////////////////////////////////////////////////////////// + // Attempt valid i2c operation multiple times ONLY on retryable fails + //////////////////////////////////////////////////////////////////////// + for ( uint8_t retry = 0; retry <= FAPI_I2C_MAX_RETRIES; ++retry ) + { + if( i_opType == DeviceFW::READ ) + { + l_err = i2cRead( i2cm, + io_buffer, + io_buflen, + &l_i2cInfo, + l_cfgData, + l_cfgSize ); + } + else if (i_opType == DeviceFW::WRITE ) + { + l_err = i2cWrite( i2cm, + io_buffer, + io_buflen, + &l_i2cInfo ); + } + + if ( nullptr == l_err ) + { + // Operation completed successfully + // break from retry loop + break; + } + else if ( !errorIsRetryable( l_err->reasonCode() ) ) + { + // Non-retryable failure + TRACFCOMP( g_trac_i2c, ERR_MRK"fapiI2cPerformOp(): Non-Nack " + "Error: rc=0x%X, tgt=0x%X, No Retry (retry=%d)", + l_err->reasonCode(), + TARGETING::get_huid(i_target), retry); + l_err->collectTrace(I2C_COMP_NAME); + + // break from retry loop + break; + } + else // Handle retryable error + { + // If op will be attempted again: save log and continue + if ( retry < FAPI_I2C_MAX_RETRIES ) + { + // Only save original retryable error + if ( nullptr == l_err_retryable ) + { + // Save original retryable error + l_err_retryable = l_err; + + TRACFCOMP( g_trac_i2c, ERR_MRK"fapiI2cPerformOp(): " + "Retryable Error rc=0x%X, eid=0x%X, tgt=0x%X, " + "retry/MAX=%d/%d. Save error and retry", + l_err_retryable->reasonCode(), + l_err_retryable->eid(), + TARGETING::get_huid(i_target), + retry, FAPI_I2C_MAX_RETRIES); + } + else + { + // Add data to original retryable error + TRACFCOMP( g_trac_i2c, ERR_MRK"fapiI2cPerformOp(): " + "Another Retryable Error rc=0x%X, eid=0x%X " + "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. " + "Delete error and retry", + l_err->reasonCode(), l_err->eid(), + l_err->plid(), TARGETING::get_huid(i_target), + retry, FAPI_I2C_MAX_RETRIES ); + + ERRORLOG::ErrlUserDetailsString( + "Another Retryable Error found") + .addToLog(l_err_retryable); + + // Delete this new retryable error + delete l_err; + l_err = nullptr; + } + + // continue to retry + continue; + } + else // no more retries: trace and break + { + TRACFCOMP( g_trac_i2c, ERR_MRK"fapiI2cPerformOp(): " + "Error rc=0x%X, eid=%d, tgt=0x%X. No More " + "Retries (retry/MAX=%d/%d). Returning Error", + l_err->reasonCode(), l_err->eid(), + TARGETING::get_huid(i_target), + retry, FAPI_I2C_MAX_RETRIES); + + // break from retry loop + break; + } + } // end of handle retryable error else leg + + } // end of retryable error loop + + // Handle saved retryable error, if any + if (l_err_retryable) + { + if (l_err) + { + // commit original retryable error with new err PLID + l_err_retryable->plid(l_err->plid()); + TRACFCOMP(g_trac_i2c, "fapiI2cPerformOp(): Committing saved " + "retryable error eid=0x%X with plid of returned err 0x%X", + l_err_retryable->eid(), l_err_retryable->plid()); + + ERRORLOG::ErrlUserDetailsTarget(i_target) + .addToLog(l_err_retryable); + l_err_retryable->collectTrace(I2C_COMP_NAME); + errlCommit(l_err_retryable, I2C_COMP_ID); + } + else + { + // Since we eventually succeeded, + // delete original retryable error + TRACUCOMP(g_trac_i2c, "fapiI2cPerformOp(): Op successful, " + "deleting saved retryable err eid=0x%X, plid=0x%X", + l_err_retryable->eid(), l_err_retryable->plid()); + + delete l_err_retryable; + l_err_retryable = nullptr; + } + } + + } while (0); + + return l_err; +} + + + +errlHndl_t i2cRead( TARGETING::Target * i_target, + void * o_buffer, + size_t & io_buffer_size, + TARGETING::ATTR_FAPI_I2C_CONTROL_INFO_type * i_i2cInfo, + uint8_t * i_offset_data, + const size_t i_offset_data_size) +{ + errlHndl_t l_err = nullptr; + + TRACUCOMP(g_trac_i2c, ENTER_MRK"i2cRead()"); + + // This i2c interface writes the offset data to the device then + // reads the value of the port w/o a stop bit in between ops + // Note: if i_offset_data_size == 0, it will skip the write + l_err = deviceOp( DeviceFW::READ, + i_target, + o_buffer, + io_buffer_size, + DEVICE_I2C_ADDRESS_OFFSET(i_i2cInfo->port, + i_i2cInfo->engine, + i_i2cInfo->devAddr, + i_offset_data_size, + i_offset_data) ); + + if( l_err ) + { + TRACFCOMP(g_trac_i2c, + ERR_MRK"fapi i2cRead(): read failed on %d/%d/0x%X offsetSize=%d " + "with eid 0x%x", i_i2cInfo->port, i_i2cInfo->engine, + i_i2cInfo->devAddr, i_offset_data_size, l_err->eid()); + + if (i_offset_data_size > 0) + { + TRACFBIN(g_trac_i2c, "i_offset_data[]", + i_offset_data, i_offset_data_size); + } + } + + TRACUCOMP(g_trac_i2c, EXIT_MRK"i2cRead"); + + return l_err; +} + + +errlHndl_t i2cWrite( TARGETING::Target * i_target, + void * i_buffer, + size_t & io_buffer_size, + TARGETING::ATTR_FAPI_I2C_CONTROL_INFO_type * i_i2cInfo ) +{ + TRACUCOMP(g_trac_i2c, ENTER_MRK"i2cWrite"); + + errlHndl_t l_err = nullptr; + + // Do the actual data write + l_err = deviceOp( DeviceFW::WRITE, + i_target, + i_buffer, + io_buffer_size, + DEVICE_I2C_ADDRESS(i_i2cInfo->port, + i_i2cInfo->engine, + i_i2cInfo->devAddr) ); + if( l_err ) + { + TRACFCOMP(g_trac_i2c, + ERR_MRK"fapi i2cWrite(): write failed on %d/%d/0x%X length %d " + "with eid 0x%x", i_i2cInfo->port, i_i2cInfo->engine, + i_i2cInfo->devAddr, io_buffer_size, l_err->eid()); + } + + + TRACUCOMP(g_trac_i2c, EXIT_MRK"i2cWrite"); + return l_err; +} + + +errlHndl_t readI2cAttributes( TARGETING::Target * i_target, + TARGETING::ATTR_FAPI_I2C_CONTROL_INFO_type & io_i2cInfo ) +{ + errlHndl_t l_err = nullptr; + + if( !(i_target->tryGetAttr<TARGETING::ATTR_FAPI_I2C_CONTROL_INFO> + (io_i2cInfo)) ) + { + TRACFCOMP( g_trac_i2c, + ERR_MRK"readI2cAttributes() - ERROR reading " + "attributes for target huid %.8X", + TARGETING::get_huid(i_target) ); + + /*@ + * @errortype + * @reasoncode I2C::I2C_ATTRIBUTE_NOT_FOUND + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid I2C::READ_I2C_ATTRIBUTES + * @userdata1 HUID of target + * @devdesc FAPI_I2C_CONTROL_INFO attribute was not found + * @custdesc A problem occurred during the IPL + * of the system. + */ + l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + I2C::READ_I2C_ATTRIBUTES, + I2C::I2C_ATTRIBUTE_NOT_FOUND, + TARGETING::get_huid(i_target), + 0, + true /*Add HB SW Callout*/ ); + + l_err->collectTrace( I2C_COMP_NAME ); + } + return l_err; +} + +}; // end namespace FAPI_I2C + diff --git a/src/usr/i2c/fapi_i2c_dd.H b/src/usr/i2c/fapi_i2c_dd.H new file mode 100644 index 000000000..e7bef8396 --- /dev/null +++ b/src/usr/i2c/fapi_i2c_dd.H @@ -0,0 +1,103 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/i2c/fapi_i2c_dd.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __FAPII2CDD_H +#define __FAPII2CDD_H + +#include <errl/errlentry.H> +#include <i2c/i2cif.H> +#include <targeting/common/targetservice.H> +#include <devicefw/driverif.H> + +namespace FAPI_I2C_DD +{ + /** + * @brief Perform a FAPI i2c operation + * + * @param[in] i_optype - Operation Type - @see devicefw/userif.H + * @param[in] i_target - Target device (contains attr with fapiI2c info) + * @param[in/out] io_buffer - Ptr to data buffer to be written/read into + * @param[in/out] io_buflen - Length of the data buffer + * @param[in] i_accessType @see devicefw/userif.H + * @param[in] i_args Device argument list. + * ConfigDataSize as size_t + * ConfigData as uint8_t* + * + * + * @return errlHndl_t NULL on success or error handle on error. + */ + errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType, + TARGETING::Target * i_target, + void * io_buffer, + size_t & io_buflen, + int64_t i_accessType, + va_list i_args); + + /** + * @brief Read from a i2c device and port + * + * @param[in] i_target - Target of the i2c master for this i2c device + * @param[in] i_data - Configuration data to write before the read + * @param[out] o_buffer - Buffer to contain what was read + * @param[in] i_i2cInfo - i2c addressing information + * + * @return errlHndl_t - Null on Success or error handle on error + */ + errlHndl_t i2cRead( TARGETING::Target * i_target, + void * o_buffer, + size_t & io_buffer_size, + TARGETING::ATTR_FAPI_I2C_CONTROL_INFO_type * i_i2cInfo, + uint8_t * i_offset_data, + const size_t i_offset_data_size ); + + /** + * @brief Write to an i2c target + * + * @param[in] i_target - Target of the i2c master for this i2c device + * @param[in] i_buffer - Buffer containing the value to write + * @param[in] io_buffer_size - Number of bytes to write + * Returns number of bytes written + * @param[in] i_i2cInfo - i2c addressing information + * + * @return errlHndl_t - NULL on Success or error handle on error + */ + errlHndl_t i2cWrite( TARGETING::Target * i_target, + void * i_buffer, + size_t & io_buffer_size, + TARGETING::ATTR_FAPI_I2C_CONTROL_INFO_type * i_i2cInfo ); + + + /** + * @brief Read the FAPI I2C attributes associated with target + * + * @param[in] i_target - Target that contains the attritutes for the device + * @param[in/out] io_i2cInfo I2C address information. + * + * @return errlHndl_t - NULL on Success or error handle on error + */ + errlHndl_t readI2cAttributes ( TARGETING::Target * i_target, + TARGETING::ATTR_FAPI_I2C_CONTROL_INFO_type &io_i2cInfo ); +}; + +#endif diff --git a/src/usr/i2c/makefile b/src/usr/i2c/makefile index a0a7e0f26..baefb1bed 100644 --- a/src/usr/i2c/makefile +++ b/src/usr/i2c/makefile @@ -31,6 +31,7 @@ include i2c.mk #include unique objects OBJS += i2c.o OBJS += $(if $(CONFIG_TPMDD),tpmdd.o,) +OBJS += fapi_i2c_dd.o SUBDIRS += test.d SUBDIRS += runtime.d |