summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatt Derksen <mderkse1@us.ibm.com>2019-09-13 15:05:45 -0500
committerWilliam G Hoffa <wghoffa@us.ibm.com>2019-09-30 15:35:10 -0500
commit09016a8a7f562b83bd3003d84fa8177eaf200378 (patch)
tree5bb1f4b31e273f17669c9692b124573aeb8d7dba /src
parent56b1dbc3ce1a7c6d45dc94515d17304d622827af (diff)
downloadtalos-hostboot-09016a8a7f562b83bd3003d84fa8177eaf200378.tar.gz
talos-hostboot-09016a8a7f562b83bd3003d84fa8177eaf200378.zip
Hostboot platform support for Explorer inband commands via i2c
Inband SRAM can be accessed via scom i2c commands. To Explorer, a register address and an internal memory address are the same thing. That allows us to execute the inband command set even if the OMI link is not active. A new attribute determinds when this inband i2c is required so it can be an easy override for lab use. By default, this i2c path will not execute when OMI links are working. Change-Id: I3f18cf78d2e88e33935f1bd241ef4e2796d36d93 RTC: 208447 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/83787 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: Daniel M Crowell <dcrowell@us.ibm.com> Reviewed-by: William G Hoffa <wghoffa@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/usr/fapi2/hwpf_fapi2_reasoncodes.H3
-rw-r--r--src/usr/expaccess/test/exptest_utils.C30
-rw-r--r--src/usr/expaccess/test/exptest_utils.H6
-rw-r--r--src/usr/expaccess/test/ocmbcommtest.H146
-rw-r--r--src/usr/fapi2/plat_mmio_access.C310
-rw-r--r--src/usr/targeting/common/xmltohb/attribute_types.xml15
-rw-r--r--src/usr/targeting/common/xmltohb/target_types.xml3
7 files changed, 481 insertions, 32 deletions
diff --git a/src/include/usr/fapi2/hwpf_fapi2_reasoncodes.H b/src/include/usr/fapi2/hwpf_fapi2_reasoncodes.H
index 2cc133468..793474322 100644
--- a/src/include/usr/fapi2/hwpf_fapi2_reasoncodes.H
+++ b/src/include/usr/fapi2/hwpf_fapi2_reasoncodes.H
@@ -73,6 +73,8 @@ namespace fapi2
MOD_FAPI2_PLAT_GET_FREQ_MCA_MHZ = 0x1E,
MOD_GET_OMI_FREQ_AND_VCO = 0x1F,
MOD_FAPI2_SPD_ACCESS = 0x20,
+ MOD_FAPI2_EXPLR_IB_I2C_READ = 0x21,
+ MOD_FAPI2_EXPLR_IB_I2C_WRITE = 0x22,
};
/**
@@ -134,6 +136,7 @@ namespace fapi2
RC_FAILED_TO_GET_RING_LIST = FAPI2_COMP_ID | 0x40,
RC_ATTR_OVERRIDE_DISALLOWED = FAPI2_COMP_ID | 0x41,
RC_UNKNOWN_OCMB_CHIP_TYPE = FAPI2_COMP_ID | 0x42,
+ RC_INVALID_BUFFER_SIZE = FAPI2_COMP_ID | 0x43,
// HWP generated errors
RC_HWP_GENERATED_ERROR = HWPF_COMP_ID | 0x0f,
diff --git a/src/usr/expaccess/test/exptest_utils.C b/src/usr/expaccess/test/exptest_utils.C
index 46421fc4a..01096716f 100644
--- a/src/usr/expaccess/test/exptest_utils.C
+++ b/src/usr/expaccess/test/exptest_utils.C
@@ -103,4 +103,34 @@ namespace exptest
mutex_unlock(l_mutex);
};
+ void disableInbandScomsOcmb(const TARGETING::TargetHandle_t i_ocmbTarget)
+ {
+ mutex_t* l_mutex = nullptr;
+
+ assert((i_ocmbTarget != nullptr),
+ "disableInbandScomsOcmb: target is NULL!");
+
+ // Verify that the target is of type OCMB_CHIP
+ TARGETING::ATTR_TYPE_type l_targetType =
+ i_ocmbTarget->getAttr<TARGETING::ATTR_TYPE>();
+ assert((l_targetType == TARGETING::TYPE_OCMB_CHIP),
+ "disableInbandScomsOcmb: target is not an OCMB chip!");
+
+ TS_INFO("disableInbandScomsOcmb: switching to use i2c on OCMB 0x%08x",
+ TARGETING::get_huid(i_ocmbTarget));
+
+ //don't mess with attributes without the mutex (just to be safe)
+ l_mutex = i_ocmbTarget->getHbMutexAttr<TARGETING::ATTR_IBSCOM_MUTEX>();
+ mutex_lock(l_mutex);
+
+ TARGETING::ScomSwitches l_switches =
+ i_ocmbTarget->getAttr<TARGETING::ATTR_SCOM_SWITCHES>();
+ l_switches.useInbandScom = 0;
+ l_switches.useI2cScom = 1;
+
+ // Modify attribute
+ i_ocmbTarget->setAttr<TARGETING::ATTR_SCOM_SWITCHES>(l_switches);
+ mutex_unlock(l_mutex);
+ };
+
}
diff --git a/src/usr/expaccess/test/exptest_utils.H b/src/usr/expaccess/test/exptest_utils.H
index a62b4de71..babba0fcf 100644
--- a/src/usr/expaccess/test/exptest_utils.H
+++ b/src/usr/expaccess/test/exptest_utils.H
@@ -53,6 +53,12 @@ TARGETING::HB_MUTEX_SERIALIZE_TEST_LOCK_ATTR getTestMutex(void);
* @param[in] i_ocmbTarget The target OCMB chip
*/
void enableInbandScomsOcmb(const TARGETING::TargetHandle_t i_ocmbTarget);
+
+/**
+ * @brief Disable inband scoms on an OCMB target (use i2c instead)
+ * @param[in] i_ocmbTarget The target OCMB chip
+ */
+void disableInbandScomsOcmb(const TARGETING::TargetHandle_t i_ocmbTarget);
}
#endif
diff --git a/src/usr/expaccess/test/ocmbcommtest.H b/src/usr/expaccess/test/ocmbcommtest.H
index b804ecb1b..3c5486a1b 100644
--- a/src/usr/expaccess/test/ocmbcommtest.H
+++ b/src/usr/expaccess/test/ocmbcommtest.H
@@ -131,11 +131,13 @@ class OCMBCommTest: public CxxTest::TestSuite
}
/**
- * @brief Test the Explorer inband command/response path
+ * @brief Send and check get_properties Explorer inband command
+ * @return Number of failures
*/
- void testOcmbInbandCmdRsp( void )
+ int sendOcmbInbandCmdRsp(bool setScomI2c)
{
errlHndl_t l_errl = nullptr;
+ uint8_t failures = 0;
// Create a vector of TARGETING::Target pointers
TARGETING::TargetHandleList l_chipList;
@@ -150,19 +152,22 @@ class OCMBCommTest: public CxxTest::TestSuite
// Create a non-destructive get_properties command
buildPropertiesGetCmd(l_cmd);
- if (!iv_serializeTestMutex)
- {
- TS_FAIL("iv_serializedTestMutex is not setup, unable to continue");
- }
- else
+ for (auto & l_ocmb: l_chipList)
{
- // Inband operations can't be run at the same time
- // atomic section >>
- mutex_lock(iv_serializeTestMutex);
-
- for (auto & l_ocmb: l_chipList)
+ do
{
- FAPI_INF("testOcmbInbandCmdRsp: testing 0x%.8X OCMB", TARGETING::get_huid(l_ocmb));
+ if (setScomI2c)
+ {
+ FAPI_INF("sendOcmbInbandCmdRsp: testing 0x%.8X OCMB using I2C", TARGETING::get_huid(l_ocmb));
+ // disable inband and use i2c when possible
+ exptest::disableInbandScomsOcmb(l_ocmb);
+ }
+ else
+ {
+ FAPI_INF("sendOcmbInbandCmdRsp: testing 0x%.8X OCMB using MMIO", TARGETING::get_huid(l_ocmb));
+ // just incase some other test disabled inband scoms
+ exptest::enableInbandScomsOcmb(l_ocmb);
+ }
fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>l_fapi2_target( l_ocmb );
@@ -175,10 +180,11 @@ class OCMBCommTest: public CxxTest::TestSuite
{
TS_FAIL("Error from putCMD for 0x%.8X target",
TARGETING::get_huid(l_ocmb));
+ failures++;
break;
}
- FAPI_INF("testOcmbInbandCmdRsp: reading response");
+ FAPI_INF("sendOcmbInbandCmdRsp: reading response");
// grab the response
FAPI_INVOKE_HWP(l_errl, mss::exp::ib::getRSP, l_fapi2_target,
@@ -188,6 +194,7 @@ class OCMBCommTest: public CxxTest::TestSuite
TS_FAIL("Error from getRSP for 0x%.8X target, plid=0x%X rc=0x%X",
TARGETING::get_huid(l_ocmb),
ERRL_GETPLID_SAFE(l_errl), ERRL_GETRC_SAFE(l_errl));
+ failures++;
break;
}
@@ -199,6 +206,7 @@ class OCMBCommTest: public CxxTest::TestSuite
{
TS_FAIL("Unexpected response length 0x%.8X (expected 0x%.8X)",
l_rsp.response_length, sizeof(FW_ADAPTER_PROPERTIES_type));
+ failures++;
break;
}
@@ -213,21 +221,121 @@ class OCMBCommTest: public CxxTest::TestSuite
{
TS_FAIL("Expected chip_version to start with 0x88, found 0x%02X",
l_fw_adapter_data.chip_version[0]);
+ failures++;
}
- }
-
- // << atomic section
- mutex_unlock(iv_serializeTestMutex);
+ } while (0);
if (l_errl)
{
+ // Commit the error as this is NOT expected and
+ // needs to be investigated
errlCommit( l_errl, TARG_COMP_ID );
}
+
+ if (setScomI2c)
+ {
+ // Default the ocmb back to inband communication
+ exptest::enableInbandScomsOcmb(l_ocmb);
+ }
}
- FAPI_INF("testOcmbInbandCmdRsp: exiting");
+
+ FAPI_INF("sendOcmbInbandCmdRsp: exiting");
+ return failures;
};
/**
+ * @brief Test the Explorer inband command/response path over MMIO
+ */
+ void testOcmbInbandCmdRspOverMMIO( void )
+ {
+ if (!iv_serializeTestMutex)
+ {
+ TS_FAIL("iv_serializedTestMutex is not setup, unable to continue");
+ }
+ else
+ {
+ // Inband operations can't be run at the same time
+ // atomic section >>
+ mutex_lock(iv_serializeTestMutex);
+
+ int failures = sendOcmbInbandCmdRsp(false);
+ if (failures)
+ {
+ TS_FAIL("testOcmbInbandCmdRspOverMMIO() failed: %d", failures);
+ }
+ mutex_unlock(iv_serializeTestMutex);
+ }
+ }
+
+ /**
+ * @brief Test the Explorer inband command/response path over I2C
+ * using ATTR_FORCE_SRAM_MMIO_OVER_I2C
+ */
+ void testOcmbInbandCmdRspOverI2c_via_force( void )
+ {
+ FAPI_INF("testOcmbInbandCmdRspOverI2c_via_force: entering");
+ if (!iv_serializeTestMutex)
+ {
+ TS_FAIL("iv_serializedTestMutex is not setup, unable to continue");
+ }
+ else
+ {
+ // Inband operations can't be run at the same time
+ // atomic section >>
+ mutex_lock(iv_serializeTestMutex);
+
+ // Set FORCE_SRAM_MMIO_OVER_I2C to change to use I2C instead of MMIO
+ TARGETING::Target * l_sys = nullptr;
+ TARGETING::targetService().getTopLevelTarget(l_sys);
+ crit_assert(l_sys != nullptr);
+
+ l_sys->setAttr<TARGETING::ATTR_FORCE_SRAM_MMIO_OVER_I2C>(0x01);
+
+ int failures = sendOcmbInbandCmdRsp(false);
+ if (failures)
+ {
+ TS_FAIL("testOcmbInbandCmdRspOverI2c_via_force() failed: %d", failures);
+ }
+
+ // Restore using MMIO instead of I2C
+ l_sys->setAttr<TARGETING::ATTR_FORCE_SRAM_MMIO_OVER_I2C>(0x00);
+
+ mutex_unlock(iv_serializeTestMutex);
+ }
+ FAPI_INF("testOcmbInbandCmdRspOverI2c_via_force: exiting");
+ }
+
+ /**
+ * @brief Test the Explorer inband command/response path over I2C
+ * using scom setting to i2c
+ */
+ void testOcmbInbandCmdRspOverI2c_via_scom_switch( void )
+ {
+ FAPI_INF("testOcmbInbandCmdRspOverI2c_via_scom_switch: entering");
+ if (!iv_serializeTestMutex)
+ {
+ TS_FAIL("iv_serializedTestMutex is not setup, unable to continue");
+ }
+ else
+ {
+ // Inband operations can't be run at the same time
+ // atomic section >>
+ mutex_lock(iv_serializeTestMutex);
+
+ // Set SCOM_SWITCHES to use i2c instead of MMMIO when
+ // running the inband cmd/rsp operations
+ int failures = sendOcmbInbandCmdRsp(true);
+ if (failures)
+ {
+ TS_FAIL("testOcmbInbandCmdRspOverI2c_via_scom_switch() failed: %d", failures);
+ }
+
+ mutex_unlock(iv_serializeTestMutex);
+ }
+ FAPI_INF("testOcmbInbandCmdRspOverI2c_via_scom_switch: exiting");
+ }
+
+ /**
* @brief Constructor
*/
OCMBCommTest() : CxxTest::TestSuite()
diff --git a/src/usr/fapi2/plat_mmio_access.C b/src/usr/fapi2/plat_mmio_access.C
index 60526761b..365aa1f22 100644
--- a/src/usr/fapi2/plat_mmio_access.C
+++ b/src/usr/fapi2/plat_mmio_access.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2018 */
+/* Contributors Listed Below - COPYRIGHT 2018,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -39,9 +39,272 @@
#include <hwpf_fapi2_reasoncodes.H>
#include <fapi2/plat_mmio_access.H>
-
namespace fapi2
{
+// Address bit that designates it as an Explorer MMIO address
+static const uint64_t EXPLR_IB_MMIO_OFFSET = 0x0000000100000000ull;
+
+// Valid I2C access to 256MB SRAM space, starts at offset 0x01000000
+static const uint64_t MIN_I2C_SRAM_SPACE_ADDRESS = 0x0000000001000000ull;
+static const uint64_t MAX_I2C_SRAM_SPACE_ADDRESS = 0x0000000001030000ull;
+
+// byte transaction sizes for i2c
+static const size_t I2C_TRANSACTION_SIZE = 4; // actual size sent
+static const size_t SCOM_I2C_TRANSACTION_SIZE = 8;
+
+// Convert MMIO to I2C address (need these bits set)
+static const uint64_t EXPLR_MMIO_TO_I2C_ADDRESS_MASK = 0xA0000000;
+
+
+/**
+ * @brief Explorer Inband read via i2c
+ * @param[in] i_target - OCMB target
+ * @param[in/out] io_data_read - buffer to be filled with read data
+ * @param[in/out] io_get_size - size of buffer (returns read size)
+ * @param[in] i_i2c_addr - i2c scom address
+ * @return errlHndl_t indicating success or failure
+ */
+errlHndl_t explrIbI2cRead(TARGETING::Target * i_target,
+ uint8_t * io_data_read,
+ size_t io_get_size,
+ const uint64_t i_i2c_addr)
+{
+ errlHndl_t l_err = nullptr;
+
+ if ( io_get_size % I2C_TRANSACTION_SIZE )
+ {
+ // invalid size expected (needs to be a multiple of I2C_TRANSACTION_SIZE)
+ FAPI_ERR("explrIbI2cRead: read size %d is not a multiple of %d",
+ io_get_size, I2C_TRANSACTION_SIZE);
+ /*@
+ * @errortype
+ * @moduleid fapi2::MOD_FAPI2_EXPLR_IB_I2C_READ
+ * @reasoncode fapi2::RC_INVALID_BUFFER_SIZE
+ * @userdata1[0:31] Buffer size
+ * @userdata1[32:63] Transaction size
+ * @userdata2[0:31] HUID of input target
+ * @userdata2[32:63] i2c_address
+ * @devdesc Invalid read buffer size, needs to be divisible by transaction size
+ * @custdesc Internal firmware error
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ fapi2::MOD_FAPI2_EXPLR_IB_I2C_READ,
+ fapi2::RC_INVALID_BUFFER_SIZE,
+ TWO_UINT32_TO_UINT64(io_get_size,
+ I2C_TRANSACTION_SIZE),
+ TWO_UINT32_TO_UINT64(
+ TARGETING::get_huid(i_target),
+ i_i2c_addr),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ l_err->collectTrace(FAPI_TRACE_NAME);
+ io_get_size = 0; // no data being read
+ }
+ else
+ {
+ FAPI_INF("explrIbI2cRead: deviceRead() starting at i2cscom address "
+ "0x%08X for %d bytes", i_i2c_addr, io_get_size);
+
+ // keep track of total bytes read
+ size_t total_bytes_read = 0;
+
+ // Increment this address after each read transaction
+ uint64_t i2cAddr = i_i2c_addr;
+
+ // scom transaction variables
+ size_t scomTransSize = SCOM_I2C_TRANSACTION_SIZE;
+ uint8_t scomReadData[SCOM_I2C_TRANSACTION_SIZE];
+
+ // Only able to read 4 bytes at a time with i2c, so
+ // need to break into multiple i2c read transactions
+ while( total_bytes_read < io_get_size )
+ {
+ FAPI_DBG("explrIbI2cRead: deviceRead() at i2cscom address 0x%08X", i2cAddr);
+ l_err = deviceOp( DeviceFW::READ,
+ i_target,
+ scomReadData,
+ scomTransSize,
+ DEVICE_I2CSCOM_ADDRESS(i2cAddr) );
+ if (l_err)
+ {
+ FAPI_ERR("explrIbI2cRead: target 0x%08X deviceRead() at address 0x%08X failed",
+ TARGETING::get_huid(i_target), i2cAddr);
+ l_err->collectTrace(FAPI_TRACE_NAME);
+ break;
+ }
+ else
+ {
+ FAPI_DBG("explrIbI2cRead: read %02X%02X%02X%02X",
+ scomReadData[4], scomReadData[5], scomReadData[6], scomReadData[7]);
+ }
+
+ // The MMIO hardware does this byteswap for us, since we are
+ // running this over i2c we must reorder the bytes here
+ io_data_read[total_bytes_read] = scomReadData[7];
+ io_data_read[total_bytes_read+1] = scomReadData[6];
+ io_data_read[total_bytes_read+2] = scomReadData[5];
+ io_data_read[total_bytes_read+3] = scomReadData[4];
+
+ // Only able to read 4 bytes at a time
+ total_bytes_read += I2C_TRANSACTION_SIZE;
+ i2cAddr += I2C_TRANSACTION_SIZE;
+
+ // make sure this value is correct for next op
+ scomTransSize = SCOM_I2C_TRANSACTION_SIZE;
+ }
+ }
+ return l_err;
+}
+
+
+/**
+ * @brief Explorer Inband write via i2c
+ * @param[in] i_target - OCMB target
+ * @param[in] i_write_data - data to write out
+ * @param[in/out] io_write_size - how much data to write (returns how much written)
+ * @param[in] i_i2c_addr - i2c scom address
+ * @return errlHndl_t indicating success or failure
+ */
+errlHndl_t explrIbI2cWrite(TARGETING::Target * i_target,
+ const uint8_t * i_write_data,
+ size_t io_write_size,
+ const uint64_t i_i2c_addr)
+{
+ errlHndl_t l_err = nullptr;
+
+ // Verify write can be divide up evenly
+ if ( io_write_size % I2C_TRANSACTION_SIZE )
+ {
+ // invalid size expected (needs to be a multiple of I2C_TRANSACTION_SIZE)
+ FAPI_ERR("explrIbI2cWrite: write size %d is not a multiple of %d",
+ io_write_size, I2C_TRANSACTION_SIZE);
+ /*@
+ * @errortype
+ * @moduleid fapi2::MOD_FAPI2_EXPLR_IB_I2C_WRITE
+ * @reasoncode fapi2::RC_INVALID_BUFFER_SIZE
+ * @userdata1[0:31] Buffer size
+ * @userdata1[32:63] Transaction size
+ * @userdata2[0:31] HUID of input target
+ * @userdata2[32:63] i2c_address
+ * @devdesc Invalid write buffer size, needs to be divisible by transaction size
+ * @custdesc Internal firmware error
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ fapi2::MOD_FAPI2_EXPLR_IB_I2C_READ,
+ fapi2::RC_INVALID_BUFFER_SIZE,
+ TWO_UINT32_TO_UINT64(io_write_size,
+ I2C_TRANSACTION_SIZE),
+ TWO_UINT32_TO_UINT64(
+ TARGETING::get_huid(i_target),
+ i_i2c_addr),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ l_err->collectTrace(FAPI_TRACE_NAME);
+ }
+ else
+ {
+ // counter for bytes written out to SRAM space
+ size_t total_bytes_written = 0;
+
+ // going to alter this address to cycle through write data
+ uint64_t i2cAddr = i_i2c_addr;
+
+ // scom transaction variables
+ size_t scomTransSize = SCOM_I2C_TRANSACTION_SIZE;
+ uint8_t scomWriteData[SCOM_I2C_TRANSACTION_SIZE];
+
+ FAPI_INF("explrIbI2cWrite: deviceWrite() starting at i2cscom address "
+ "0x%08X for %d bytes", i_i2c_addr, io_write_size);
+
+ // Only able to write 4 bytes at a time with i2c,
+ // so need to break into multiple i2c write transactions
+ while( total_bytes_written < io_write_size )
+ {
+ memset(scomWriteData, 0x00, SCOM_I2C_TRANSACTION_SIZE);
+
+ // Only last four bytes are actually written out
+ // NOTE: MMIO hardware does this byteswap for us, but since we
+ // are running this over i2c we must reorder the bytes here
+ scomWriteData[7] = i_write_data[total_bytes_written];
+ scomWriteData[6] = i_write_data[total_bytes_written+1];
+ scomWriteData[5] = i_write_data[total_bytes_written+2];
+ scomWriteData[4] = i_write_data[total_bytes_written+3];
+
+ l_err = deviceOp( DeviceFW::WRITE,
+ i_target,
+ scomWriteData,
+ scomTransSize,
+ DEVICE_I2CSCOM_ADDRESS(i2cAddr) );
+ if (l_err)
+ {
+ FAPI_ERR("explrIbI2cWrite: i2cscom write(0x%02X%02X%02X%02X) at address 0x%08X failed",
+ scomWriteData[4], scomWriteData[5], scomWriteData[6], scomWriteData[7], i2cAddr);
+ l_err->collectTrace(FAPI_TRACE_NAME);
+ break;
+ }
+ // Really only doing 4-byte transactions
+ i2cAddr += I2C_TRANSACTION_SIZE;
+ total_bytes_written += I2C_TRANSACTION_SIZE;
+
+ // Update for next scom operation
+ scomTransSize = SCOM_I2C_TRANSACTION_SIZE;
+ }
+ }
+ return l_err;
+}
+
+/**
+ * @brief Checks if all the conditions are met to allow i2c
+ * operation instead of MMIO.
+ * @param[in] i_ocmb - OCMB target
+ * @param[in] i_mmioAddress - address passed into get/putMMIO
+ * @return true if i2c should be used instead of MMIO
+ */
+bool useI2cInsteadOfMmio( const TARGETING::Target * i_ocmb,
+ const uint64_t i_mmioAddress )
+{
+ bool useI2c = false; // default to use MMIO
+
+ uint8_t attrAllowedI2c = 0;
+
+ // Check force i2c attribute first
+ TARGETING::Target* l_sys = nullptr;
+ TARGETING::targetService().getTopLevelTarget(l_sys);
+ crit_assert(l_sys != nullptr);
+ attrAllowedI2c = l_sys->getAttr<TARGETING::ATTR_FORCE_SRAM_MMIO_OVER_I2C>();
+
+ // If not forced to use i2c, then check if that is the current scom setting
+ if (!attrAllowedI2c)
+ {
+ // The SCOM_SWITCHES attribute will keep track of when it is safe
+ // to access the ocmb via inband vs when we should do accesses over
+ // i2c. Use this attribute to decide which we want to use.
+ auto ocmb_info = i_ocmb->getAttr<TARGETING::ATTR_SCOM_SWITCHES>();
+ if (!ocmb_info.useInbandScom)
+ {
+ attrAllowedI2c = 1;
+ }
+ }
+
+ // Attribute settings must allow i2c operation before checking
+ // for a valid address range
+ if (attrAllowedI2c)
+ {
+ // Verify address is within valid SRAM range
+ if ( ((i_mmioAddress & 0x0F00000000) == EXPLR_IB_MMIO_OFFSET) &&
+ ((i_mmioAddress & 0x0FFFFFFFF) >= MIN_I2C_SRAM_SPACE_ADDRESS) &&
+ ((i_mmioAddress & 0x0FFFFFFFF) <= MAX_I2C_SRAM_SPACE_ADDRESS) )
+ {
+ useI2c = true;
+ }
+ else
+ {
+ FAPI_INF("0x%08X OCMB address 0x%.8X is outside of SRAM range so using mmio",
+ TARGETING::get_huid(i_ocmb), i_mmioAddress);
+ }
+ }
+
+ return useI2c;
+}
+
//------------------------------------------------------------------------------
// HW Communication Functions to be implemented at the platform layer.
//------------------------------------------------------------------------------
@@ -83,12 +346,22 @@ ReturnCode platGetMMIO( const Target<TARGET_TYPE_ALL>& i_target,
break; //return with error
}
- // call MMIO driver
- l_err = DeviceFW::deviceRead(l_target,
- l_data_read,
- l_get_size,
- DEVICE_MMIO_ADDRESS(i_mmioAddr, i_transSize));
-
+ // Run mmio if inband i2c isn't enabled or address is outside of SRAM range
+ if ( !useI2cInsteadOfMmio(l_target, i_mmioAddr) )
+ {
+ // call MMIO driver
+ l_err = DeviceFW::deviceRead(l_target,
+ l_data_read,
+ l_get_size,
+ DEVICE_MMIO_ADDRESS(i_mmioAddr, i_transSize));
+ }
+ else
+ {
+ // Use i2c instead of MMMIO
+ // Explorer i2c addresses are actually 32-bit and need 0xA at the beginning
+ uint64_t i2cAddr = (i_mmioAddr & 0x00000000FFFFFFFF) | EXPLR_MMIO_TO_I2C_ADDRESS_MASK;
+ l_err = explrIbI2cRead(l_target, l_data_read, l_get_size, i2cAddr);
+ }
if (l_traceit)
{
// Only trace the first 8 bytes of data read
@@ -167,11 +440,22 @@ ReturnCode platPutMMIO( const Target<TARGET_TYPE_ALL>& i_target,
std::copy(i_data.begin(), i_data.end(), l_writeDataPtr);
size_t l_dataSize = i_data.size();
- // call MMIO driver
- l_err = DeviceFW::deviceWrite(l_target,
- l_writeDataPtr,
- l_dataSize,
- DEVICE_MMIO_ADDRESS(i_mmioAddr, i_transSize));
+ // Run mmio if inband i2c isn't enabled or address is outside of SRAM range
+ if ( !useI2cInsteadOfMmio(l_target, i_mmioAddr) )
+ {
+ // call MMIO driver
+ l_err = DeviceFW::deviceWrite(l_target,
+ l_writeDataPtr,
+ l_dataSize,
+ DEVICE_MMIO_ADDRESS(i_mmioAddr, i_transSize));
+ }
+ else
+ {
+ // Address is an Explorer SRAM address, so I2C will work
+ // Explorer i2c addresses are actually 32-bit and need 0xA at the beginning
+ uint64_t i2cAddr = (i_mmioAddr & 0x00000000FFFFFFFF) | EXPLR_MMIO_TO_I2C_ADDRESS_MASK;
+ l_err = explrIbI2cWrite(l_target, l_writeDataPtr, l_dataSize, i2cAddr);
+ }
if (l_traceit)
{
// trace the first 8 bytes of written data
diff --git a/src/usr/targeting/common/xmltohb/attribute_types.xml b/src/usr/targeting/common/xmltohb/attribute_types.xml
index cea2726d9..9b4d6764e 100644
--- a/src/usr/targeting/common/xmltohb/attribute_types.xml
+++ b/src/usr/targeting/common/xmltohb/attribute_types.xml
@@ -1805,6 +1805,21 @@
</attribute>
<attribute>
+ <id>FORCE_SRAM_MMIO_OVER_I2C</id>
+ <description>
+ Force inband SRAM access to be over I2C instead of MMIO
+ This is a way to get data when the MMIO path is not working
+ (0x00 = use normal path, 0x01 = force i2c path)
+ </description>
+ <simpleType>
+ <uint8_t/>
+ </simpleType>
+ <persistency>volatile-zeroed</persistency>
+ <readable/>
+ <writeable/>
+ </attribute>
+
+ <attribute>
<id>FREQ_CORE_CEILING_MHZ</id>
<description>
The maximum core frequency in MHz.
diff --git a/src/usr/targeting/common/xmltohb/target_types.xml b/src/usr/targeting/common/xmltohb/target_types.xml
index c5b466ebf..bc0858b5d 100644
--- a/src/usr/targeting/common/xmltohb/target_types.xml
+++ b/src/usr/targeting/common/xmltohb/target_types.xml
@@ -1860,6 +1860,9 @@
<id>FORCE_NVDIMM_RESET</id>
</attribute>
<attribute>
+ <id>FORCE_SRAM_MMIO_OVER_I2C</id>
+ </attribute>
+ <attribute>
<id>FREQ_CORE_CEILING_MHZ</id>
</attribute>
<attribute>
OpenPOWER on IntegriCloud