summaryrefslogtreecommitdiffstats
path: root/src/usr/i2c
diff options
context:
space:
mode:
authorChristian Geddes <crgeddes@us.ibm.com>2019-01-23 14:43:37 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2019-02-16 09:10:13 -0600
commite6832f74ac222be90b6719a33613863698239ce4 (patch)
tree58f0f0010bd984b11c8ce200e3dabae2b0bbd91a /src/usr/i2c
parentbc80fc6b84359fa03c4212162e3e548dadcd8a9c (diff)
downloadtalos-hostboot-e6832f74ac222be90b6719a33613863698239ce4.tar.gz
talos-hostboot-e6832f74ac222be90b6719a33613863698239ce4.zip
Add new path in EEPROM device op to allow reading from new EECACHE
Recently a new EECACHE section was introduced to Hostboot. This section gets populated with a copy of every PRIMARY_VPD eeprom (someday could contain other eeprom roles also) during host_discover_targets. This commit add support to allow users to select where they want to perform their EEPROM device operation. If they pass CACHE to the deviceOp macro then a read will come from the pnor cache, writes will write to pnor cache and then also write to the eeprom HW. If HARDWARE is passed in then reads and writes will be directly done on the eeprom hardware. If AUTOSELECT is passed the code will check our cache to see if we have a copy of the eeprom in question, if we have a copy we will go the CACHE path, if no copy exists we will go the HARDWARE path. Along with this change some reorganization was done w/ the eeprom related files. RTC: 196805 Change-Id: If2c4e5d3e338a1a10780740c1a019eb4af003b73 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/70822 Reviewed-by: Matt Derksen <mderkse1@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Roland Veloz <rveloz@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/i2c')
-rw-r--r--src/usr/i2c/eepromCache.C668
-rw-r--r--src/usr/i2c/eepromCache.H115
-rw-r--r--src/usr/i2c/eeprom_utils.C800
-rwxr-xr-xsrc/usr/i2c/eepromdd.C2239
-rw-r--r--src/usr/i2c/eepromdd_hardware.C1364
-rw-r--r--[-rwxr-xr-x]src/usr/i2c/eepromdd_hardware.H (renamed from src/usr/i2c/eepromdd.H)153
-rw-r--r--src/usr/i2c/errlud_i2c.C1
-rw-r--r--src/usr/i2c/errlud_i2c.H3
-rw-r--r--src/usr/i2c/i2c.mk3
-rw-r--r--src/usr/i2c/makefile1
-rwxr-xr-xsrc/usr/i2c/test/eepromddtest.H20
11 files changed, 2934 insertions, 2433 deletions
diff --git a/src/usr/i2c/eepromCache.C b/src/usr/i2c/eepromCache.C
index 72541df33..dc8bb15db 100644
--- a/src/usr/i2c/eepromCache.C
+++ b/src/usr/i2c/eepromCache.C
@@ -24,176 +24,239 @@
/* IBM_PROLOG_END_TAG */
#include <builtins.h>
+#include <stdarg.h>
+#include <sys/mm.h>
+#include <limits.h>
#include <devicefw/driverif.H>
-#include "eepromdd.H"
#include <errl/errlmanager.H>
#include <fsi/fsiif.H>
#include "i2c.H"
+#include "eepromCache.H"
#include <i2c/i2cif.H>
#include <i2c/eepromif.H>
-#include <i2c/i2creasoncodes.H>
-#include <i2c/eepromCache_const.H>
+#include <i2c/eepromddreasoncodes.H>
#include <initservice/initserviceif.H>
#include <initservice/initsvcreasoncodes.H>
-#include <sys/mm.h>
-#include <limits.h>
#include <pnor/pnorif.H>
-#include <stdarg.h>
#include <vpd/vpd_if.H>
+#include <errl/errludtarget.H>
-extern trace_desc_t* g_trac_i2c;
+extern trace_desc_t* g_trac_eeprom;
-// #define TRACSSCOMP(args...) TRACFCOMP(args)
+//#define TRACSSCOMP(args...) TRACFCOMP(args)
#define TRACSSCOMP(args...)
-namespace I2C
+namespace EEPROM
{
-uint64_t g_eecachePnorVaddr;
-uint64_t g_eecachePnorSize;
-
+// Global variable that will keep track of the virtual address which
+// points to the start of the EECACHE section, and the size of this section.
+// It is handy to keep these around so we do not need to look them up in the
+// pnor code everytime.
+uint64_t g_eecachePnorVaddr = 0;
+uint64_t g_eecachePnorSize = 0;
+
+// Global map which is used as a way to quickly look up the virtual address
+// of a given eeprom's cached data in EECACHE section
+// Key = eepromRecordHeader with unique info filled out
+// Value = virtual address pointing to the cached eeprom data in pnor
+std::map<eepromRecordHeader, uint64_t> g_cachedEeproms;
+
+// Any time we access either any of the global variables defined above we want
+// to wrap the call in this mutex to avoid multi-threading issues
mutex_t g_eecacheMutex = MUTEX_INITIALIZER;
-/**
- * @brief Write all 0xFFs to the EECACHE section in pnor to clear out the
- * eeprom cache information.
- * @return errlHndl_t
- */
-errlHndl_t clearEEcache()
+uint64_t lookupEepromAddr(const eepromRecordHeader& i_eepromRecordHeader)
{
- errlHndl_t l_errl = nullptr;
-
- memset(reinterpret_cast<void *>(g_eecachePnorVaddr), 0xFF, g_eecachePnorSize);
-
- // Flush the page to make sure it gets to the PNOR
- int rc = mm_remove_pages( FLUSH, reinterpret_cast<void *>(g_eecachePnorVaddr), g_eecachePnorSize );
+ uint64_t l_vaddr = 0;
+ std::map<eepromRecordHeader, uint64_t>::iterator l_it;
+ // Wrap lookup in mutex because reads are not thread safe
+ mutex_lock(&g_eecacheMutex);
+ l_it = g_cachedEeproms.find(i_eepromRecordHeader);
+ mutex_unlock(&g_eecacheMutex);
- if( rc )
+ if(l_it != g_cachedEeproms.end())
{
- TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush contents write to pnor! rc=%d",rc);
- /*@
- * @errortype
- * @moduleid I2C_CLEAR_EECACHE
- * @reasoncode I2C_FAILED_TO_FLUSH_CONTENTS
- * @userdata1 Requested Address
- * @userdata2 rc from mm_remove_pages
- * @devdesc clearEEcache mm_remove_pages FLUSH failed
- */
- l_errl = new ERRORLOG::ErrlEntry(
- ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- I2C_CLEAR_EECACHE,
- I2C_FAILED_TO_FLUSH_CONTENTS,
- (uint64_t)g_eecachePnorVaddr,
- TO_UINT64(rc),
- ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
-
- l_errl->collectTrace(I2C_COMP_NAME);
+ l_vaddr = l_it->second;
}
- return l_errl;
+ return l_vaddr;
}
-/**
- * @brief Lookup I2C information for given eeprom, check if eeprom exists in cache.
- * If it exists already determine if any updates are required. If it is not
- * in the cache yet, add it to the cache.
- *
- * @param[in] i_target Presence detect target
- * @param[in] i_present Describes whether or not target is present
- * ( CANNOT RELY ON HWAS_STATE!! )
- * @param[in] i_eepromType Describes which EEPROM associated to the target
- * that is being requested to cache. (PRIMARY/BACKUP etc)
- * @return errlHndl_t
- */
-errlHndl_t cacheEeprom(TARGETING::Target* i_target,
- bool i_present,
- EEPROM::eeprom_chip_types_t i_eepromType)
+errlHndl_t buildEepromRecordHeader(TARGETING::Target * i_target,
+ eeprom_addr_t & io_eepromInfo,
+ eepromRecordHeader & o_eepromRecordHeader)
{
- TRACSSCOMP( g_trac_i2c, "cacheEeprom() ENTER Target HUID 0x%.08X ", TARGETING::get_huid(i_target));
- errlHndl_t l_errl = nullptr;
+
TARGETING::Target * l_muxTarget = nullptr;
TARGETING::Target * l_i2cMasterTarget = nullptr;
TARGETING::TargetService& l_targetService = TARGETING::targetService();
-
- EEPROM::eeprom_addr_t l_eepromInfo;
- eecacheSectionHeader * l_eecacheSectionHeaderPtr;
-
- // Initially assume we will want to update both the entry in the header
- // as well as the contents in the body of the EECACHE section
- bool l_updateHeader = true;
- bool l_updateContents = true;
+ errlHndl_t l_errl = nullptr;
do{
- // eepromReadAttributes keys off the eepromRole value
- // to determine what attribute to lookup to get eeprom info
- l_eepromInfo.eepromRole = i_eepromType;
- l_errl = eepromReadAttributes(i_target, l_eepromInfo);
+ l_errl = eepromReadAttributes(i_target, io_eepromInfo);
if(l_errl)
{
- TRACFCOMP( g_trac_i2c,
- "cacheEeprom() error occured reading eeprom attributes for eepromType %d, target 0x%.08X, returning!!",
- i_eepromType,
+ TRACFCOMP( g_trac_eeprom,
+ "buildEepromRecordHeader() error occured reading eeprom attributes for eepromType %d, target 0x%.08X, returning!!",
+ io_eepromInfo.eepromRole,
TARGETING::get_huid(i_target));
- l_errl->collectTrace(I2C_COMP_NAME);
+ l_errl->collectTrace(EEPROM_COMP_NAME);
break;
}
// Grab the I2C mux target so we can read the HUID, if the target is NULL we will not be able
// to lookup attribute to uniquely ID this eeprom so we will not cache it
- l_muxTarget = l_targetService.toTarget( l_eepromInfo.i2cMuxPath);
+ l_muxTarget = l_targetService.toTarget( io_eepromInfo.i2cMuxPath);
if(l_muxTarget == nullptr)
{
- TRACFCOMP( g_trac_i2c,
- "cacheEeprom() Mux target associated with target 0x%.08X resolved to a nullptr , check attribute for eepromType %d. Skipping Cache",
+ TRACFCOMP( g_trac_eeprom,
+ "buildEepromRecordHeader() Mux target associated with target 0x%.08X resolved to a nullptr , check attribute for eepromType %d. Skipping Cache",
TARGETING::get_huid(i_target),
- i_eepromType);
+ io_eepromInfo.eepromRole);
/*@
* @errortype
- * @moduleid I2C_CACHE_EEPROM
- * @reasoncode I2C_MUX_TARGET_NOT_FOUND
+ * @moduleid EEPROM_CACHE_EEPROM
+ * @reasoncode EEPROM_I2C_MUX_PATH_ERROR
* @userdata1 HUID of target we want to cache
- * @userdata2[0:31] Type of EEPROM we are caching
- * @userdata2[32:63] Boolean is target present or not
- * @devdesc cacheEeprom invalid mux target
+ * @userdata2 Type of EEPROM we are caching
+ * @devdesc buildEepromRecordHeader invalid mux target
*/
l_errl = new ERRORLOG::ErrlEntry(
ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- I2C_CACHE_EEPROM,
- I2C_MUX_TARGET_NOT_FOUND,
+ EEPROM_CACHE_EEPROM,
+ EEPROM_I2C_MUX_PATH_ERROR,
TARGETING::get_huid(i_target),
- TWO_UINT32_TO_UINT64(i_eepromType, i_present),
+ io_eepromInfo.eepromRole,
ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
- l_errl->collectTrace(I2C_COMP_NAME);
+ l_errl->collectTrace(EEPROM_COMP_NAME);
break;
}
// Grab the I2C master target so we can read the HUID, if the target is NULL we will not be able
// to lookup attribute to uniquely ID this eeprom so we will not cache it
- l_i2cMasterTarget = l_targetService.toTarget( l_eepromInfo.i2cMasterPath );
+ l_i2cMasterTarget = l_targetService.toTarget( io_eepromInfo.i2cMasterPath );
if(l_i2cMasterTarget == nullptr)
{
- TRACFCOMP( g_trac_i2c,
- "cacheEeprom() I2C Master target associated with target 0x%.08X resolved to a nullptr , check attribute for eepromType %d. Skipping Cache ",
+ TRACFCOMP( g_trac_eeprom,
+ "buildEepromRecordHeader() I2C Master target associated with target 0x%.08X resolved to a nullptr , check attribute for eepromType %d. Skipping Cache ",
TARGETING::get_huid(i_target),
- i_eepromType);
+ io_eepromInfo.eepromRole);
/*@
* @errortype
- * @moduleid I2C_CACHE_EEPROM
- * @reasoncode INVALID_MASTER_TARGET
+ * @moduleid EEPROM_CACHE_EEPROM
+ * @reasoncode EEPROM_I2C_MASTER_PATH_ERROR
* @userdata1 HUID of target we want to cache
- * @userdata2[0:31] Type of EEPROM we are caching
- * @userdata2[32:63] Boolean is target present or not
- * @devdesc cacheEeprom invalid master target
+ * @userdata2 Type of EEPROM we are caching
+ * @devdesc buildEepromRecordHeader invalid master target
*/
l_errl = new ERRORLOG::ErrlEntry(
ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- I2C_CACHE_EEPROM,
- INVALID_MASTER_TARGET,
+ EEPROM_CACHE_EEPROM,
+ EEPROM_I2C_MASTER_PATH_ERROR,
TARGETING::get_huid(i_target),
- TWO_UINT32_TO_UINT64(i_eepromType, i_present),
+ io_eepromInfo.eepromRole,
ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
- l_errl->collectTrace(I2C_COMP_NAME);
+ l_errl->collectTrace(EEPROM_COMP_NAME);
+ break;
+ }
+
+ // This is what we will compare w/ when we are going through the existing
+ // caches in the eeprom to see if we have already cached something
+ // Or if no matches are found we will copy this into the header
+ o_eepromRecordHeader.completeRecord.i2c_master_huid = l_i2cMasterTarget->getAttr<TARGETING::ATTR_HUID>();
+ o_eepromRecordHeader.completeRecord.port = static_cast<uint8_t>(io_eepromInfo.port);
+ o_eepromRecordHeader.completeRecord.engine = static_cast<uint8_t>(io_eepromInfo.engine);
+ o_eepromRecordHeader.completeRecord.devAddr = static_cast<uint8_t>(io_eepromInfo.devAddr);
+ o_eepromRecordHeader.completeRecord.mux_select = static_cast<uint8_t>(io_eepromInfo.i2cMuxBusSelector);
+ o_eepromRecordHeader.completeRecord.cache_copy_size = static_cast<uint32_t>(io_eepromInfo.devSize_KB);
+
+ // Do not set valid bit nor internal offset here as we do not have
+ // enough information availible to determine
+
+ }while(0);
+
+ return l_errl;
+}
+
+// Do NOT allow adding/removing eeproms to cache during RT
+#ifndef __HOSTBOOT_RUNTIME
+
+bool addEepromToCachedList(const eepromRecordHeader & i_eepromRecordHeader)
+{
+ bool l_matchFound = true;
+ std::map<eepromRecordHeader, uint64_t>::iterator it;
+
+ // Map accesses are not thread safe, make sure this is always wrapped in mutex
+ mutex_lock(&g_eecacheMutex);
+
+ if(g_cachedEeproms.find(i_eepromRecordHeader) == g_cachedEeproms.end())
+ {
+ g_cachedEeproms[i_eepromRecordHeader] = g_eecachePnorVaddr + i_eepromRecordHeader.completeRecord.internal_offset;
+ TRACSSCOMP( g_trac_eeprom, "addEepromToCachedList() Adding I2CM Huid: 0x%.08X, Port: 0x%.02X, Engine: 0x%.02X, Dev Addr: 0x%.02X, Mux Select: 0x%.02X, Size: 0x%.08X to g_cachedEeproms",
+ i_eepromRecordHeader.completeRecord.i2c_master_huid,
+ i_eepromRecordHeader.completeRecord.port,
+ i_eepromRecordHeader.completeRecord.engine,
+ i_eepromRecordHeader.completeRecord.devAddr,
+ i_eepromRecordHeader.completeRecord.mux_select,
+ i_eepromRecordHeader.completeRecord.cache_copy_size);
+ l_matchFound = false;
+ }
+
+ mutex_unlock(&g_eecacheMutex);
+
+ return l_matchFound;
+}
+
+/**
+ * @brief Lookup I2C information for given eeprom, check if eeprom exists in cache.
+ * If it exists already determine if any updates are required. If it is not
+ * in the cache yet, add it to the cache.
+ *
+ * @param[in] i_target Presence detect target
+ * @param[in] i_present Describes whether or not target is present
+ * ( CANNOT RELY ON HWAS_STATE!! )
+ * @param[in] i_eepromType Describes which EEPROM associated to the target
+ * that is being requested to cache. (PRIMARY/BACKUP etc)
+ * @return errlHndl_t
+ */
+errlHndl_t cacheEeprom(TARGETING::Target* i_target,
+ bool i_present,
+ EEPROM::EEPROM_ROLE i_eepromType)
+{
+ TRACSSCOMP( g_trac_eeprom, "cacheEeprom() ENTER Target HUID 0x%.08X ", TARGETING::get_huid(i_target));
+ errlHndl_t l_errl = nullptr;
+
+ EEPROM::eeprom_addr_t l_eepromInfo;
+ eecacheSectionHeader * l_eecacheSectionHeaderPtr;
+ eepromRecordHeader l_eepromRecordHeader;
+
+ // Initially assume we will want to update both the entry in the header
+ // as well as the contents in the body of the EECACHE section
+ bool l_updateHeader = true;
+ bool l_updateContents = true;
+
+ do{
+ // eepromReadAttributes keys off the eepromRole value
+ // to determine what attribute to lookup to get eeprom info
+ l_eepromInfo.eepromRole = i_eepromType;
+
+ // if the target is present, then this record is valid
+ l_eepromRecordHeader.completeRecord.cached_copy_valid = i_present;
+
+ // buildEepromRecordHeader will call eepromReadAttributes to fill in l_eepromInfo
+ // with info looked up in attributes and also fill in l_eepromRecordHeader
+ l_errl = buildEepromRecordHeader(i_target, l_eepromInfo, l_eepromRecordHeader);
+
+ TRACDBIN( g_trac_eeprom, "cacheEeprom: l_eepromRecordHeader currently ",
+ &l_eepromRecordHeader,
+ sizeof(eepromRecordHeader));
+
+ if(l_errl)
+ {
+ // buildEepromRecordHeader should have traced any relavent information if
+ // is was needed, just break out and pass the error along
break;
}
@@ -207,14 +270,14 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
if(l_errl)
{
- TRACFCOMP( g_trac_i2c, "cacheEeprom() Failed while looking up the EECACHE section in PNOR!!");
+ TRACFCOMP( g_trac_eeprom, "cacheEeprom() Failed while looking up the EECACHE section in PNOR!!");
break;
}
mutex_lock(&g_eecacheMutex);
g_eecachePnorVaddr = l_sectionInfo.vaddr;
g_eecachePnorSize = l_sectionInfo.size;
- TRACFCOMP( g_trac_i2c, "cacheEeprom() vaddr for EECACHE start = 0x%lx , size = 0x%lx!!",
+ TRACFCOMP( g_trac_eeprom, "cacheEeprom() vaddr for EECACHE start = 0x%lx , size = 0x%lx!!",
g_eecachePnorVaddr, g_eecachePnorSize);
mutex_unlock(&g_eecacheMutex);
}
@@ -232,7 +295,7 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
// if nothing has been cached before then version should
// be set to be the latest version of the struct available
l_eecacheSectionHeaderPtr->version = EECACHE_VERSION_LATEST;
- TRACFCOMP( g_trac_i2c,
+ TRACFCOMP( g_trac_eeprom,
"cacheEeprom() Found Empty Cache, set version of cache structure to be 0x%.02x",
EECACHE_VERSION_1);
}
@@ -244,30 +307,17 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
// This means the start of first eeprom's cached data will be immediately
// following the end of the EECACHE header.
l_eecacheSectionHeaderPtr->end_of_cache = sizeof(eecacheSectionHeader);
- TRACFCOMP( g_trac_i2c,
+ TRACFCOMP( g_trac_eeprom,
"cacheEeprom() Found Empty Cache, set end of cache to be 0x%.04x (End of ToC)",
sizeof(eecacheSectionHeader));
}
- // This is what we will compare w/ when we are going through the existing
- // caches in the eeprom to see if we have already cached something
- // Or if no matches are found we will copy this into the header
- eepromRecordHeader l_eepromRecord = {l_i2cMasterTarget->getAttr<TARGETING::ATTR_HUID>(),
- (uint8_t)l_eepromInfo.port,
- (uint8_t)l_eepromInfo.engine,
- (uint8_t)l_eepromInfo.devAddr,
- l_muxTarget->getAttr<TARGETING::ATTR_HUID>(),
- l_eepromInfo.i2cMuxBusSelector,
- (uint8_t)l_eepromInfo.devSize_KB,
- 0, // Default internal offset to be 0
- i_present};
-
size_t l_eepromLen = l_eepromInfo.devSize_KB * KILOBYTE;
// Parse through PNOR section header to determine if a copy of this
// eeprom already exists, or if we need to add it, and where we should add it
// if we need to.
- eepromRecordHeader * l_recordHeaderToUpdate;
+ eepromRecordHeader * l_recordHeaderToUpdate = nullptr;
// Initialize this to an INVALID value. This way we catch the case where
// cache has 50 records and we cannot add anymore. In that case l_recordHeaderToUpdateIndex
@@ -279,77 +329,132 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
// Keep track of current record so we can use outside for loop
l_recordHeaderToUpdate = &l_eecacheSectionHeaderPtr->recordHeaders[i];
- // If internal_offset is non-zero then we will assume this address has been filled
- if(l_recordHeaderToUpdate->internal_offset != UNSET_INTERNAL_OFFSET_VALUE)
+
+ // If internal_offset is UNSET_INTERNAL_OFFSET_VALUE then we will assume this address not been filled
+ if(l_recordHeaderToUpdate->completeRecord.internal_offset == UNSET_INTERNAL_OFFSET_VALUE)
+ {
+ assert((l_eecacheSectionHeaderPtr->end_of_cache + l_eepromLen) < g_eecachePnorSize,
+ "Sum of system EEPROMs is larger than space allocated for EECACHE pnor section");
+
+ l_recordHeaderToUpdateIndex = i;
+ // Set this new eepromRecord's offset within the EECACHE PNOR section
+ // to be the current "end of cache" offset in the toc.
+ l_eepromRecordHeader.completeRecord.internal_offset = l_eecacheSectionHeaderPtr->end_of_cache;
+ l_eecacheSectionHeaderPtr->end_of_cache += l_eepromLen;
+ l_updateContents = i_present;
+ break;
+ }
+
+ // Compare the eeprom record we are checking against the eeprom records we are iterating through
+ // but ignore the last 9 bytes which have chip size, the offset into this pnor section where the
+ // record exists, and a byte that tells us if its valid or not
+ if( memcmp(l_recordHeaderToUpdate, &l_eepromRecordHeader, NUM_BYTE_UNIQUE_ID ) == 0 )
{
- // Compare the eeprom record we are checking against the eeprom records we are iterating through
- // but ignore the last 9 bytes which have chip size, the offset into this pnor section where the
- // record exists, and a byte that tells us if its valid or not
- if( memcmp(l_recordHeaderToUpdate, &l_eepromRecord, RECORD_COMPARE_SIZE ) == 0 )
+ l_recordHeaderToUpdateIndex = i;
+
+ if( l_recordHeaderToUpdate->completeRecord.cache_copy_size != l_eepromRecordHeader.completeRecord.cache_copy_size)
{
- l_recordHeaderToUpdateIndex = i;
- if( l_recordHeaderToUpdate->record_size != l_eepromRecord.record_size)
+ // This indicates that a part size has changed , caching
+ // algorithm cannot account for size changes.
+ // Invalidate entire cache and TI to trigger re-ipl
+ l_errl = PNOR::clearSection(PNOR::EECACHE);
+
+ // If there was an error clearing the cache commit is because we are TIing
+ if(l_errl)
{
- // This indicates that a part size has changed , caching
- // algorithm cannot account for size changes.
- // Invalidate entire cache and TI to trigger re-ipl
- l_errl = clearEEcache();
-
- // If there was an error clearing the cache commit is because we are TIing
- if(l_errl)
- {
- errlCommit(l_errl, I2C_COMP_ID);
- }
-
- INITSERVICE::doShutdown(INITSERVICE::SHUTDOWN_DO_RECONFIG_LOOP);
+ errlCommit(l_errl, EEPROM_COMP_ID);
}
- if(l_recordHeaderToUpdate->record_valid)
+ /*@
+ * @errortype ERRORLOG::ERRL_SEV_PREDICTIVE
+ * @moduleid EEPROM_CACHE_EEPROM
+ * @reasoncode EEPROM_NEW_DEVICE_DETECTED
+ * @userdata1[0:31] Old Size of Eeprom
+ * @userdata1[32:63] New Size of Eeprom
+ * @userdata2[0:31] HUID of I2C Master
+ * @userdata2[32:39] Port
+ * @userdata2[40:47] Engine
+ * @userdata2[48:55] HUID of I2C Master
+ * @userdata2[56:63] HUID of I2C Master
+ * @devdesc New part has likely been loaded into the system.
+ * @custdesc Firmware detected new part and is restarting
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_PREDICTIVE,
+ EEPROM_CACHE_EEPROM,
+ EEPROM_NEW_DEVICE_DETECTED,
+ TWO_UINT32_TO_UINT64(l_recordHeaderToUpdate->completeRecord.cache_copy_size ,
+ l_eepromRecordHeader.completeRecord.cache_copy_size),
+ TWO_UINT32_TO_UINT64(l_eepromRecordHeader.completeRecord.i2c_master_huid,
+ TWO_UINT16_TO_UINT32(
+ TWO_UINT8_TO_UINT16(l_eepromRecordHeader.completeRecord.port,
+ l_eepromRecordHeader.completeRecord.engine),
+ TWO_UINT8_TO_UINT16(l_eepromRecordHeader.completeRecord.devAddr,
+ l_eepromRecordHeader.completeRecord.mux_select))));
+ errlCommit(l_errl, EEPROM_COMP_ID);
+
+ #ifdef CONFIG_CONSOLE
+ CONSOLE::displayf(EEPROM_COMP_NAME,
+ "New EEPROM size detected for an existing part, clearing EEPROM cache and performing reconfig loop");
+ #endif
+
+ INITSERVICE::doShutdown(INITSERVICE::SHUTDOWN_DO_RECONFIG_LOOP);
+ }
+
+ //
+ // At this point we have found a match in the PNOR but we need
+ // to decide what all needs an update
+ //
+
+ // Stash the internal_offset of the section we found in so we can add
+ // this record to g_cachedEeproms for later use
+ l_eepromRecordHeader.completeRecord.internal_offset =
+ l_recordHeaderToUpdate->completeRecord.internal_offset;
+
+
+ if(l_recordHeaderToUpdate->completeRecord.cached_copy_valid)
+ {
+ // If the existing eeprom record is valid, then only update the
+ // contents if the SN/PN for current HW do not match the eeprom
+ // record. (target must be present to cache)
+
+ // TODO RTC:203788 add lookup for PN and SN matches
+ //if( !i_present || PNandSNMatch )
{
- // If the existing eeprom record is valid, then only update the
- // contents if the SN/PN for current HW do not match the eeprom
- // record. (target must be present to cache)
-
- // TODO RTC:203788 add lookup for PN and SN matches
- //if( !i_present || PNandSNMatch )
- {
- l_updateContents = false;
- }
-
- // If target is present there is nothing in the
- // header to update
- if( i_present )
- {
- l_updateHeader = false;
- }
+ l_updateContents = false;
}
- else if(!i_present)
+
+ // If target is present there is nothing in the
+ // header to update
+ if( i_present )
{
- // If the target is not present, then do not update contents or header
- l_updateContents = false;
l_updateHeader = false;
}
-
- TRACSSCOMP( g_trac_i2c, "cacheEeprom() already found copy for eeprom role %d for target w/ HUID 0x.%08X",
- i_eepromType , TARGETING::get_huid(i_target));
- break;
}
- }
- else
- {
- assert((l_eecacheSectionHeaderPtr->end_of_cache + l_eepromLen) < g_eecachePnorSize,
- "Sum of system EEPROMs is larger than space allocated for EECACHE pnor section");
+ else if(!i_present)
+ {
+ // If the target is not present, then do not update contents or header
+ l_updateContents = false;
+ l_updateHeader = false;
+ }
- l_recordHeaderToUpdateIndex = i;
- // Set this new eepromRecord's offset within the EECACHE PNOR section
- // to be the current "end of cache" offset in the toc.
- l_eepromRecord.internal_offset = l_eecacheSectionHeaderPtr->end_of_cache;
- l_eecacheSectionHeaderPtr->end_of_cache += l_eepromLen;
- l_updateContents = i_present;
+ TRACSSCOMP( g_trac_eeprom, "cacheEeprom() already found copy for eeprom role %d for target w/ HUID 0x.%08X",
+ i_eepromType , TARGETING::get_huid(i_target));
break;
}
}
+ if(!addEepromToCachedList(l_eepromRecordHeader))
+ {
+ TRACSSCOMP( g_trac_eeprom, "cacheEeprom() Eeprom w/ Role %d, HUID 0x.%08X added to cached list",
+ i_eepromType , TARGETING::get_huid(i_target));
+ }
+ else
+ {
+ TRACSSCOMP( g_trac_eeprom, "cacheEeprom() Eeprom w/ Role %d, HUID 0x.%08X already in cached list",
+ i_eepromType , TARGETING::get_huid(i_target));
+ }
+
// Above we have determined whether the contents of the eeprom at
// hand need to have their contents updated. Only do the following
@@ -364,22 +469,22 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
l_tmpBuffer = malloc(l_eepromLen);
void * l_internalSectionAddr =
- reinterpret_cast<uint8_t *>(l_eecacheSectionHeaderPtr) + l_eepromRecord.internal_offset;
+ reinterpret_cast<uint8_t *>(l_eecacheSectionHeaderPtr) + l_eepromRecordHeader.completeRecord.internal_offset;
- TRACSSCOMP( g_trac_i2c, "cacheEeprom() passing the following into deviceOp eeprom address : huid 0x%.08X length 0x%.08X" ,
- get_huid(i_target), l_eepromLen);
+ TRACSSCOMP( g_trac_eeprom, "cacheEeprom() passing the following into deviceOp eeprom address : huid 0x%.08X length 0x%.08X vaddr %p" ,
+ get_huid(i_target), l_eepromLen, l_internalSectionAddr);
// Copy vpd contents to cache
l_errl = deviceOp(DeviceFW::READ,
i_target,
l_tmpBuffer,
l_eepromLen,
- DEVICE_EEPROM_ADDRESS(i_eepromType, 0));
+ DEVICE_EEPROM_ADDRESS(i_eepromType, 0, VPD::SEEPROM));
// If an error occurred during the eeprom read then free the tmp buffer and break out
if( l_errl)
{
- TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error occured reading from EEPROM type %d for HUID 0x%.08X!",
+ TRACFCOMP(g_trac_eeprom,ERR_MRK"cacheEeprom: Error occured reading from EEPROM type %d for HUID 0x%.08X!",
i_eepromType,get_huid(i_target));
free(l_tmpBuffer);
break;
@@ -392,26 +497,26 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
int rc = mm_remove_pages( FLUSH, l_internalSectionAddr, l_eepromLen );
if( rc )
{
- TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush contents write to pnor! rc=%d",rc);
+ TRACFCOMP(g_trac_eeprom,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush contents write to pnor! rc=%d",rc);
/*@
* @errortype
- * @moduleid I2C_CACHE_EEPROM
- * @reasoncode I2C_FAILED_TO_FLUSH_CONTENTS
+ * @moduleid EEPROM_CACHE_EEPROM
+ * @reasoncode EEPROM_FAILED_TO_FLUSH_CONTENTS
* @userdata1 Requested Address
* @userdata2 rc from mm_remove_pages
* @devdesc cacheEeprom mm_remove_pages FLUSH failed
*/
l_errl = new ERRORLOG::ErrlEntry(
ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- I2C_CACHE_EEPROM,
- I2C_FAILED_TO_FLUSH_CONTENTS,
+ EEPROM_CACHE_EEPROM,
+ EEPROM_FAILED_TO_FLUSH_CONTENTS,
(uint64_t)l_internalSectionAddr,
TO_UINT64(rc),
ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
}
else
{
- TRACSSCOMP( g_trac_i2c, "cacheEeprom() %.08X bytes of eeprom data related to %.08X have been written to %p" ,
+ TRACSSCOMP( g_trac_eeprom, "cacheEeprom() %.08X bytes of eeprom data related to %.08X have been written to %p" ,
l_eepromLen, get_huid(i_target), l_internalSectionAddr);
}
@@ -430,27 +535,30 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
// the eeprom's header entry if we were told to do so.
if(l_updateHeader)
{
+ TRACDBIN( g_trac_eeprom, "cacheEeprom: l_eecacheSectionHeaderPtr currently ",
+ l_eecacheSectionHeaderPtr,
+ sizeof(eecacheSectionHeader));
// Copy the local eepromRecord header struct with the info about the
// new eeprom we want to add to the cache to the open slot we found
- memcpy(l_recordHeaderToUpdate , &l_eepromRecord, sizeof(eepromRecordHeader));
+ memcpy(l_recordHeaderToUpdate , &l_eepromRecordHeader, sizeof(eepromRecordHeader));
// Flush the page to make sure it gets to the PNOR
int rc = mm_remove_pages( FLUSH, l_recordHeaderToUpdate, sizeof(eepromRecordHeader) );
if( rc )
{
- TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush header write to pnor, rc=%d",rc);
+ TRACFCOMP(g_trac_eeprom,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush header write to pnor, rc=%d",rc);
/*@
* @errortype
- * @moduleid I2C_CACHE_EEPROM
- * @reasoncode I2C_FAILED_TO_FLUSH_HEADER
+ * @moduleid EEPROM_CACHE_EEPROM
+ * @reasoncode EEPROM_FAILED_TO_FLUSH_HEADER
* @userdata1 Requested Address
* @userdata2 rc from mm_remove_pages
* @devdesc cacheEeprom mm_remove_pages FLUSH failed
*/
l_errl = new ERRORLOG::ErrlEntry(
ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- I2C_CACHE_EEPROM,
- I2C_FAILED_TO_FLUSH_HEADER,
+ EEPROM_CACHE_EEPROM,
+ EEPROM_FAILED_TO_FLUSH_HEADER,
(uint64_t)l_recordHeaderToUpdate,
TO_UINT64(rc),
ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
@@ -458,12 +566,10 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
}
}
- TRACDBIN( g_trac_i2c, "cacheEeprom: l_eecacheSectionHeaderPtr currently ",
- l_eecacheSectionHeaderPtr,
- sizeof(eecacheSectionHeader));
+
}while(0);
- TRACSSCOMP( g_trac_i2c, "cacheEeprom() EXIT Target HUID 0x%.08X ", TARGETING::get_huid(i_target));
+ TRACSSCOMP( g_trac_eeprom, "cacheEeprom() EXIT Target HUID 0x%.08X ", TARGETING::get_huid(i_target));
return l_errl;
}
@@ -498,9 +604,9 @@ errlHndl_t genericI2CEepromCache(DeviceFW::OperationType i_opType,
bool l_present = (bool)va_arg(i_args,uint64_t);
// second param is the type of EEPROM type we wish to cache (PRIMARY vs BACKUP etc)
- EEPROM::eeprom_chip_types_t l_eepromType = (EEPROM::eeprom_chip_types_t)va_arg(i_args,uint64_t);
+ EEPROM::EEPROM_ROLE l_eepromType = (EEPROM::EEPROM_ROLE)va_arg(i_args,uint64_t);
- TRACSSCOMP( g_trac_i2c, ENTER_MRK"genericI2CEepromCache() "
+ TRACSSCOMP( g_trac_eeprom, ENTER_MRK"genericI2CEepromCache() "
"Target HUID 0x%.08X Enter", TARGETING::get_huid(i_target));
do{
@@ -508,7 +614,7 @@ errlHndl_t genericI2CEepromCache(DeviceFW::OperationType i_opType,
l_errl = cacheEeprom(i_target, l_present, l_eepromType);
if(l_errl)
{
- TRACFCOMP(g_trac_i2c,
+ TRACFCOMP(g_trac_eeprom,
ERR_MRK"cacheEeprom: An error occured while attempting to cache eeprom for 0x%.08X",
TARGETING::get_huid(i_target));
break;
@@ -516,7 +622,7 @@ errlHndl_t genericI2CEepromCache(DeviceFW::OperationType i_opType,
}while(0);
- TRACSSCOMP( g_trac_i2c, EXIT_MRK"genericI2CEepromCache() "
+ TRACSSCOMP( g_trac_eeprom, EXIT_MRK"genericI2CEepromCache() "
"Target HUID 0x%.08X EXIT", TARGETING::get_huid(i_target));
return l_errl;
@@ -537,4 +643,164 @@ DEVICE_REGISTER_ROUTE( DeviceFW::READ,
TARGETING::TYPE_DIMM,
genericI2CEepromCache );
+#endif
+
+errlHndl_t eepromPerformOpCache(DeviceFW::OperationType i_opType,
+ TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t i_buflen,
+ eeprom_addr_t &i_eepromInfo)
+{
+ errlHndl_t l_errl = nullptr;
+ eepromRecordHeader l_eepromRecordHeader;
+
+ do{
+
+ TRACSSCOMP( g_trac_eeprom, ENTER_MRK"eepromPerformOpCache() "
+ "Target HUID 0x%.08X Enter", TARGETING::get_huid(i_target));
+
+ l_errl = buildEepromRecordHeader(i_target, i_eepromInfo, l_eepromRecordHeader);
+
+ if(l_errl)
+ {
+ // buildEepromRecordHeader should have traced any relavent information if
+ // it was needed, just break out and pass the error along
+ break;
+ }
+
+ uint64_t l_eepromCacheVaddr = lookupEepromAddr(l_eepromRecordHeader);
+
+ // Ensure that a copy of the eeprom exists in our map of cached eeproms
+ if(l_eepromCacheVaddr)
+ {
+ TRACSSCOMP( g_trac_eeprom, "eepromPerformOpCache() "
+ "Performing %s on target 0x%.08X offset 0x%lx length 0x%x vaddr 0x%lx",
+ (i_opType == DeviceFW::READ) ? "READ" : "WRITE",
+ TARGETING::get_huid(i_target),
+ i_eepromInfo.offset, i_buflen, l_eepromCacheVaddr);
+
+ // Make sure that offset + buflen are less than the total size of the eeprom
+ if(i_eepromInfo.offset + i_buflen > (l_eepromRecordHeader.completeRecord.cache_copy_size * KILOBYTE))
+ {
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"eepromPerformOpCache: i_eepromInfo.offset + i_offset is greater than size of eeprom (0x%x KB)",
+ l_eepromRecordHeader.completeRecord.cache_copy_size);
+ /*@
+ * @errortype
+ * @moduleid EEPROM_CACHE_PERFORM_OP
+ * @reasoncode EEPROM_OVERFLOW_ERROR
+ * @userdata1 Length of Operation
+ * @userdata2 Offset we are attempting to read/write
+ * @custdesc Soft error in Firmware
+ * @devdesc cacheEeprom invalid op type
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_CACHE_PERFORM_OP,
+ EEPROM_OVERFLOW_ERROR,
+ TO_UINT64(i_buflen),
+ TO_UINT64(i_eepromInfo.offset),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_errl);
+ l_errl->collectTrace( EEPROM_COMP_NAME );
+
+ break;
+ }
+
+ if(i_opType == DeviceFW::READ)
+ {
+ memcpy(io_buffer, reinterpret_cast<void *>(l_eepromCacheVaddr + i_eepromInfo.offset), i_buflen);
+ }
+ else if(i_opType == DeviceFW::WRITE)
+ {
+ memcpy(reinterpret_cast<void *>(l_eepromCacheVaddr + i_eepromInfo.offset), io_buffer, i_buflen);
+
+ #ifndef __HOSTBOOT_RUNTIME
+
+ // Perform flush to ensure pnor is updated
+ int rc = mm_remove_pages( FLUSH,
+ reinterpret_cast<void *>(l_eepromCacheVaddr + i_eepromInfo.offset),
+ i_buflen );
+ if( rc )
+ {
+ TRACFCOMP(g_trac_eeprom,ERR_MRK"eepromPerformOpCache: Error from mm_remove_pages trying for flush contents write to pnor! rc=%d",rc);
+ /*@
+ * @errortype
+ * @moduleid EEPROM_CACHE_PERFORM_OP
+ * @reasoncode EEPROM_FAILED_TO_FLUSH_CONTENTS
+ * @userdata1 Requested Address
+ * @userdata2 rc from mm_remove_pages
+ * @devdesc cacheEeprom mm_remove_pages FLUSH failed
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_CACHE_PERFORM_OP,
+ EEPROM_FAILED_TO_FLUSH_CONTENTS,
+ (l_eepromCacheVaddr + i_eepromInfo.offset),
+ TO_UINT64(rc),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ l_errl->collectTrace( EEPROM_COMP_NAME );
+ }
+ #endif //__HOSTBOOT_RUNTIME
+ }
+ else
+ {
+ TRACFCOMP(g_trac_eeprom,ERR_MRK"eepromPerformOpCache: Invalid OP_TYPE passed to function, i_opType=%d", i_opType);
+ /*@
+ * @errortype
+ * @moduleid EEPROM_CACHE_PERFORM_OP
+ * @reasoncode EEPROM_INVALID_OPERATION
+ * @userdata1[0:31] Op Type that was invalid
+ * @userdata1[32:63] Eeprom Role
+ * @userdata2 Offset we are attempting to perfrom op on
+ * @custdesc Soft error in Firmware
+ * @devdesc cacheEeprom invalid op type
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_CACHE_PERFORM_OP,
+ EEPROM_INVALID_OPERATION,
+ TWO_UINT32_TO_UINT64(i_opType,
+ i_eepromInfo.eepromRole),
+ TO_UINT64(i_eepromInfo.offset),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_errl);
+ l_errl->collectTrace( EEPROM_COMP_NAME );
+ }
+ }
+ else
+ {
+ TRACFCOMP( g_trac_eeprom,"eepromPerformOpCache: Failed to find entry in cache for 0x%.08X, %s failed",
+ TARGETING::get_huid(i_target),
+ (i_opType == DeviceFW::READ) ? "READ" : "WRITE");
+ /*@
+ * @errortype
+ * @moduleid EEPROM_CACHE_PERFORM_OP
+ * @reasoncode EEPROM_NOT_IN_CACHE
+ * @userdata1[0:31] Op Type
+ * @userdata1[32:63] Eeprom Role
+ * @userdata2 Offset we are attempting to read/write
+ * @custdesc Soft error in Firmware
+ * @devdesc Tried to lookup eeprom not in cache
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_CACHE_PERFORM_OP,
+ EEPROM_NOT_IN_CACHE,
+ TWO_UINT32_TO_UINT64(i_opType,
+ i_eepromInfo.eepromRole),
+ TO_UINT64(i_eepromInfo.offset),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_errl);
+ l_errl->collectTrace( EEPROM_COMP_NAME );
+ }
+
+ TRACSSCOMP( g_trac_eeprom, EXIT_MRK"eepromPerformOpCache() "
+ "Target HUID 0x%.08X Exit", TARGETING::get_huid(i_target));
+
+ }while(0);
+
+ return l_errl;
+}
+
} \ No newline at end of file
diff --git a/src/usr/i2c/eepromCache.H b/src/usr/i2c/eepromCache.H
new file mode 100644
index 000000000..0e0be7368
--- /dev/null
+++ b/src/usr/i2c/eepromCache.H
@@ -0,0 +1,115 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/i2c/eepromCache.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2019 */
+/* [+] 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 __EEPROM_CACHE_H
+#define __EEPROM_CACHE_H
+
+#include <i2c/eeprom_const.H>
+#include <errl/errlentry.H>
+
+namespace EEPROM
+{
+
+/**
+*
+* @brief Perform a read or write operation on an eeprom record inside EEACHE
+*
+*
+* @param[in] i_opType - Operation Type - See DeviceFW::OperationType in
+* driververif.H
+*
+* @param[in] i_target - Target device associated w/ the EEPROM.
+*
+* @param[in/out] io_buffer
+* INPUT: Pointer to the data that will be written to the target
+* device.
+* OUTPUT: Pointer to the data that was read from the target device.
+*
+* @param[in] i_buflen
+* INPUT: Length of the buffer to be written to target device or
+* length of buffer to be read from target device.
+*
+* @param [in] i_eepromInfo struct containing information needed to perform
+* operation on the given i2c eeprom. NOTE It is expected that
+* eepromRole and offset have been filled out in this struct
+* prior to passing it into this function
+*
+* @return errlHndl_t - nullptr if successful, otherwise a pointer to the
+* error log.
+*
+*/
+errlHndl_t eepromPerformOpCache(DeviceFW::OperationType i_opType,
+ TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t i_buflen,
+ eeprom_addr_t &i_eepromInfo);
+
+/**
+*
+* @brief Build up a struct that is used to compare cached eeprom entries
+* in the EECACHE section. Each eeprom will get an entry in the
+* eepromRecordHeader order in the EECACHE section header
+*
+* @param[in] i_target - Target device associated w/ the EEPROM.
+*
+* @param [in/out] io_eepromInfo struct containing information needed to perform
+* operation on the given i2c eeprom. NOTE It is expected that
+* eepromRole has been filled out in this struct prior to passing
+* it into this function
+* @param [out] o_eepromRecordHeader struct that will be populated with infromation
+* that can be used to determine if the eeprom has been cached yet or not,
+* or for looking up an eeprom we want to write to/ read from.
+*
+* @pre It is expected that io_i2cInfo.eepromRole will have a valid role set
+*
+* @post After function o_eepromRecordHeader will be filled in with information
+* found while looking up the eeprom info from the target's attributes.
+* o_eepromRecordHeader can be used to see if a cached copy exists
+*
+* @return errlHndl_t - nullptr if successful, otherwise a pointer to the
+* error log.
+*
+*/
+errlHndl_t buildEepromRecordHeader(TARGETING::Target * i_target,
+ eeprom_addr_t & io_eepromInfo,
+ eepromRecordHeader & o_eepromRecordHeader);
+
+/**
+*
+* @brief Perform a lookup on the global map g_cachedEeproms to get a
+* virtual address for a given EEPROM
+*
+* @param[in] i_eepromRecordHeader
+*
+* @pre It is expected that i_eepromRecordHeader has valid information for
+* the uniqueID (i2cm_huid, port, engine, devAddr, mux_select)
+*
+* @return uint64_t virtual address pointing to the cached eeprom data in pnor
+*
+*/
+uint64_t lookupEepromAddr(const eepromRecordHeader & i_eepromRecordHeader);
+
+}
+
+#endif \ No newline at end of file
diff --git a/src/usr/i2c/eeprom_utils.C b/src/usr/i2c/eeprom_utils.C
new file mode 100644
index 000000000..806a0cf31
--- /dev/null
+++ b/src/usr/i2c/eeprom_utils.C
@@ -0,0 +1,800 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/i2c/eeprom_utils.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2019 */
+/* [+] 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 */
+#include <i2c/eepromif.H>
+#include <i2c/i2cif.H>
+#include <errl/errlmanager.H>
+#include <errl/errludstring.H>
+#include <i2c/eepromddreasoncodes.H>
+#include <i2c/eeprom_const.H>
+#include "i2c_common.H"
+
+
+// ----------------------------------------------
+// Trace definitions
+// ----------------------------------------------
+trace_desc_t* g_trac_eeprom = NULL;
+TRAC_INIT( & g_trac_eeprom, EEPROM_COMP_NAME, KILOBYTE );
+
+// Easy macro replace for unit testing
+//#define TRACUCOMP(args...) TRACFCOMP(args)
+#define TRACUCOMP(args...)
+
+namespace EEPROM
+{
+
+#ifndef __HOSTBOOT_RUNTIME
+//-------------------------------------------------------------------
+//eepromPresence
+//-------------------------------------------------------------------
+bool eepromPresence ( TARGETING::Target * i_target )
+{
+ TRACUCOMP(g_trac_eeprom, ENTER_MRK"eepromPresence()");
+
+ errlHndl_t err = NULL;
+ bool l_present = false;
+ TARGETING::Target * i2cMasterTarget = NULL;
+
+ eeprom_addr_t i2cInfo;
+
+ i2cInfo.eepromRole = EEPROM::VPD_PRIMARY;
+ i2cInfo.offset = 0;
+ do
+ {
+
+ // Read Attributes needed to complete the operation
+ err = eepromReadAttributes( i_target,
+ i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"Error in eepromPresence::eepromReadAttributes()");
+ break;
+ }
+
+ // Check to see if we need to find a new target for
+ // the I2C Master
+ err = eepromGetI2CMasterTarget( i_target,
+ i2cInfo,
+ i2cMasterTarget );
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"Error in eepromPresence::eepromGetI2Cmaster()");
+ break;
+ }
+
+ //Check for the target at the I2C level
+ l_present = I2C::i2cPresence(i2cMasterTarget,
+ i2cInfo.port,
+ i2cInfo.engine,
+ i2cInfo.devAddr,
+ i2cInfo.i2cMuxBusSelector,
+ i2cInfo.i2cMuxPath);
+
+ if( !l_present )
+ {
+ TRACDCOMP(g_trac_eeprom,
+ ERR_MRK"i2cPresence returned false! chip NOT present!");
+ break;
+ }
+
+ } while( 0 );
+
+ // If there was an error commit the error log
+ if( err )
+ {
+ errlCommit( err, I2C_COMP_ID );
+ }
+
+ TRACDCOMP(g_trac_eeprom, EXIT_MRK"eepromPresence()");
+ return l_present;
+}
+#endif // __HOSTBOOT_RUNTIME
+
+/**
+ *
+ * @brief A useful utility to dump (trace out) the EepromVpdPrimaryInfo data.
+ * Use as needed.
+ *
+ * @param [in] i_i2cInfo - The EepromVpdPrimaryInfo data to dump for user
+ *
+ */
+void dumpEepromData(const TARGETING::EepromVpdPrimaryInfo & i_i2cInfo)
+{
+ TRACFCOMP (g_trac_eeprom, INFO_MRK"EepromVpdPrimaryInfo data: "
+ "engine=%d, port=%d, devAddr=0X%X, writePageSize=%d, "
+ "maxMemorySizeKB=0x%X, chipCount=%d, writeCycleTime=%d",
+ i_i2cInfo.engine, i_i2cInfo.port, i_i2cInfo.devAddr,
+ i_i2cInfo.writePageSize, i_i2cInfo.maxMemorySizeKB,
+ i_i2cInfo.chipCount, i_i2cInfo.writeCycleTime);
+
+ char* l_masterPath = i_i2cInfo.i2cMasterPath.toString();
+ char* l_muxPath = i_i2cInfo.i2cMuxPath.toString();
+ TRACFCOMP (g_trac_eeprom, INFO_MRK"EepromVpdPrimaryInfo data cont.: "
+ "masterPath=%s, muxSelector=0x%X, muxPath=%s",
+ l_masterPath, i_i2cInfo.i2cMuxBusSelector, l_muxPath);
+
+ free(l_masterPath);
+ free(l_muxPath);
+ l_masterPath = l_muxPath = nullptr;
+}
+
+
+/**
+ *
+ * @brief A useful utility to dump (trace out) the eeprom_addr_t data.
+ * Use as needed.
+ *
+ * @param [in] i_i2cInfo - The eeprom_addr_t data to dump for user
+ *
+ */
+void dumpEepromData(const eeprom_addr_t & i_i2cInfo)
+{
+ TRACFCOMP (g_trac_eeprom, INFO_MRK"eeprom_addr_t data: \n"
+ "engine=%d, port=%d, devAddr=0X%X, writePageSize=%d, \n"
+ "devSize_KB=0x%X, chipCount=%d, writeCycleTime=%d \n",
+ i_i2cInfo.engine, i_i2cInfo.port, i_i2cInfo.devAddr,
+ i_i2cInfo.writePageSize, i_i2cInfo.devSize_KB,
+ i_i2cInfo.chipCount, i_i2cInfo.writeCycleTime);
+
+ char* l_masterPath = i_i2cInfo.i2cMasterPath.toString();
+ char* l_muxPath = i_i2cInfo.i2cMuxPath.toString();
+ TRACFCOMP (g_trac_eeprom, INFO_MRK"eeprom_addr_t data cont.: \n"
+ "masterPath=%s, muxSelector=0x%X, muxPath=%s \n",
+ l_masterPath, i_i2cInfo.i2cMuxBusSelector, l_muxPath);
+
+ free(l_masterPath);
+ free(l_muxPath);
+ l_masterPath = l_muxPath = nullptr;
+}
+
+
+// ------------------------------------------------------------------
+// eepromReadAttributes
+// ------------------------------------------------------------------
+errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
+ eeprom_addr_t & o_i2cInfo )
+{
+ errlHndl_t err = NULL;
+ bool fail_reading_attribute = false;
+
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromReadAttributes()" );
+
+ // This variable will be used to hold the EEPROM attribute data
+ // Note: each 'EepromVpd' struct is kept the same via the attributes
+ // so will be copying each to eepromData to save code space
+ TARGETING::EepromVpdPrimaryInfo eepromData;
+
+ do
+ {
+
+ switch (o_i2cInfo.eepromRole )
+ {
+ case VPD_PRIMARY:
+ if( !( i_target->
+ tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO>
+ ( eepromData ) ) )
+
+ {
+ fail_reading_attribute = true;
+ }
+ break;
+
+ case VPD_BACKUP:
+
+ if( !(i_target->
+ tryGetAttr<TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO>
+ ( reinterpret_cast<
+ TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO_type&>
+ ( eepromData) ) ) )
+ {
+ fail_reading_attribute = true;
+ }
+ break;
+
+ case SBE_PRIMARY:
+ if( !(i_target->
+ tryGetAttr<TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO>
+ ( reinterpret_cast<
+ TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO_type&>
+ ( eepromData) ) ) )
+ {
+ fail_reading_attribute = true;
+ }
+ break;
+
+ case SBE_BACKUP:
+ if( (!i_target->
+ tryGetAttr<TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO>
+ ( reinterpret_cast<
+ TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO_type&>
+ ( eepromData) ) ) )
+ {
+ fail_reading_attribute = true;
+ }
+ break;
+
+ default:
+ TRACFCOMP( g_trac_eeprom,ERR_MRK"eepromReadAttributes() - "
+ "Invalid chip (%d) to read attributes from!",
+ o_i2cInfo.eepromRole );
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_INVALID_CHIP
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_READATTRIBUTES
+ * @userdata1 EEPROM Chip
+ * @userdata2 HUID of target
+ * @devdesc Invalid EEPROM chip to access
+ */
+ err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_READATTRIBUTES,
+ EEPROM_INVALID_CHIP,
+ o_i2cInfo.eepromRole,
+ TARGETING::get_huid(i_target),
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( EEPROM_COMP_NAME );
+
+ break;
+ }
+
+ // Check if Attribute Data was found
+ if( fail_reading_attribute == true )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromReadAttributes() - ERROR reading "
+ "attributes for eeprom role %d!",
+ o_i2cInfo.eepromRole );
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_ATTR_INFO_NOT_FOUND
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_READATTRIBUTES
+ * @userdata1 HUID of target
+ * @userdata2 EEPROM chip
+ * @devdesc EEPROM attribute was not found
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_READATTRIBUTES,
+ EEPROM_ATTR_INFO_NOT_FOUND,
+ TARGETING::get_huid(i_target),
+ o_i2cInfo.eepromRole);
+
+ // Could be FSP or HB code's fault
+ err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
+ HWAS::SRCI_PRIORITY_MED);
+ err->addProcedureCallout(HWAS::EPUB_PRC_SP_CODE,
+ HWAS::SRCI_PRIORITY_MED);
+
+ err->collectTrace( EEPROM_COMP_NAME );
+
+ break;
+
+ }
+
+ // Successful reading of Attribute, so extract the data
+ o_i2cInfo.port = eepromData.port;
+ o_i2cInfo.devAddr = eepromData.devAddr;
+ o_i2cInfo.engine = eepromData.engine;
+ o_i2cInfo.i2cMasterPath = eepromData.i2cMasterPath;
+ o_i2cInfo.writePageSize = eepromData.writePageSize;
+ o_i2cInfo.devSize_KB = eepromData.maxMemorySizeKB;
+ o_i2cInfo.chipCount = eepromData.chipCount;
+ o_i2cInfo.writeCycleTime = eepromData.writeCycleTime;
+ o_i2cInfo.i2cMuxBusSelector = eepromData.i2cMuxBusSelector;
+ o_i2cInfo.i2cMuxPath = eepromData.i2cMuxPath;
+
+ // Convert attribute info to eeprom_addr_size_t enum
+ if ( eepromData.byteAddrOffset == 0x3 )
+ {
+ o_i2cInfo.addrSize = ONE_BYTE_ADDR;
+ }
+ else if ( eepromData.byteAddrOffset == 0x2 )
+ {
+ o_i2cInfo.addrSize = TWO_BYTE_ADDR;
+ }
+ else if ( eepromData.byteAddrOffset == 0x1 )
+ {
+ o_i2cInfo.addrSize = ONE_BYTE_ADDR_PAGESELECT;
+ }
+ else if ( eepromData.byteAddrOffset == 0x0 )
+ {
+ o_i2cInfo.addrSize = ZERO_BYTE_ADDR;
+ }
+ else
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromReadAttributes() - INVALID ADDRESS "
+ "OFFSET SIZE %d!",
+ o_i2cInfo.addrSize );
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_INVALID_ADDR_OFFSET_SIZE
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_READATTRIBUTES
+ * @userdata1 HUID of target
+ * @userdata2 Address Offset Size
+ * @devdesc Invalid address offset size
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_READATTRIBUTES,
+ EEPROM_INVALID_ADDR_OFFSET_SIZE,
+ TARGETING::get_huid(i_target),
+ o_i2cInfo.addrSize,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( EEPROM_COMP_NAME );
+
+ break;
+
+ }
+
+ } while( 0 );
+
+ TRACUCOMP(g_trac_eeprom,"eepromReadAttributes() tgt=0x%X, %d/%d/0x%X "
+ "dsKb=0x%X, aS=%d (%d)",
+ TARGETING::get_huid(i_target),
+ o_i2cInfo.port, o_i2cInfo.engine, o_i2cInfo.devAddr,
+ o_i2cInfo.devSize_KB, o_i2cInfo.addrSize,
+ eepromData.byteAddrOffset);
+
+
+
+ // Printing mux info separately, if combined, nothing is displayed
+ char* l_muxPath = o_i2cInfo.i2cMuxPath.toString();
+ TRACFCOMP(g_trac_eeprom, "eepromReadAttributes(): "
+ "muxSelector=0x%X, muxPath=%s",
+ o_i2cInfo.i2cMuxBusSelector,
+ l_muxPath);
+ free(l_muxPath);
+ l_muxPath = nullptr;
+
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromReadAttributes()" );
+
+ return err;
+} // end eepromReadAttributes
+
+
+// ------------------------------------------------------------------
+// eepromGetI2CMasterTarget
+// ------------------------------------------------------------------
+errlHndl_t eepromGetI2CMasterTarget ( TARGETING::Target * i_target,
+ const eeprom_addr_t & i_i2cInfo,
+ TARGETING::Target * &o_target )
+{
+ errlHndl_t err = NULL;
+ o_target = NULL;
+
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromGetI2CMasterTarget()" );
+
+ do
+ {
+ TARGETING::TargetService& tS = TARGETING::targetService();
+
+ // The path from i_target to its I2C Master was read from the
+ // attribute via eepromReadAttributes() and passed to this function
+ // in i_i2cInfo.i2cMasterPath
+
+ // check that the path exists
+ bool exists = false;
+ tS.exists( i_i2cInfo.i2cMasterPath,
+ exists );
+
+ if( !exists )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromGetI2CMasterTarget() - "
+ "i2cMasterPath attribute path doesn't exist!" );
+
+ // Compress the entity path
+ uint64_t l_epCompressed = 0;
+ for( uint32_t i = 0; i < i_i2cInfo.i2cMasterPath.size(); i++ )
+ {
+ // Can only fit 4 path elements into 64 bits
+ if ( i <= 3 )
+ {
+ // Path element: type:8 instance:8
+ l_epCompressed |=
+ i_i2cInfo.i2cMasterPath[i].type << (16*(3-i));
+ l_epCompressed |=
+ i_i2cInfo.i2cMasterPath[i].instance << ((16*(3-i))-8);
+ }
+
+ // Always trace all of the info even if we cannot fit it in error log
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromGetI2CMasterTarget() - "
+ "i_i2cInfo.i2cMasterPath[%d].type = %.02X i_i2cInfo.i2cMasterPath[%d].instance = %.02X",
+ i, i_i2cInfo.i2cMasterPath[i].type, i, i_i2cInfo.i2cMasterPath[i].instance );
+
+ }
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_I2C_MASTER_PATH_ERROR
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_GETI2CMASTERTARGET
+ * @userdata1[00:31] Attribute Chip Type Enum
+ * @userdata1[32:63] HUID of target
+ * @userdata2 Compressed Entity Path
+ * @devdesc I2C master entity path doesn't exist.
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_GETI2CMASTERTARGET,
+ EEPROM_I2C_MASTER_PATH_ERROR,
+ TWO_UINT32_TO_UINT64(
+ i_i2cInfo.eepromRole,
+ TARGETING::get_huid(i_target) ),
+ l_epCompressed,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( EEPROM_COMP_NAME );
+
+ char* l_masterPath = i_i2cInfo.i2cMasterPath.toString();
+ ERRORLOG::ErrlUserDetailsString(l_masterPath).addToLog(err);
+ free(l_masterPath);
+ l_masterPath = nullptr;
+
+ break;
+ }
+
+ // Since it exists, convert to a target
+ o_target = tS.toTarget( i_i2cInfo.i2cMasterPath );
+
+ if( NULL == o_target )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromGetI2CMasterTarget() - I2C Master "
+ "Path target was NULL!" );
+
+ // Compress the entity path
+ uint64_t l_epCompressed = 0;
+ for( uint32_t i = 0; i < i_i2cInfo.i2cMasterPath.size(); i++ )
+ {
+ // Can only fit 4 path elements into 64 bits
+ if ( i <= 3 )
+ {
+ // Path element: type:8 instance:8
+ l_epCompressed |=
+ i_i2cInfo.i2cMasterPath[i].type << (16*(3-i));
+ l_epCompressed |=
+ i_i2cInfo.i2cMasterPath[i].instance << ((16*(3-i))-8);
+ }
+
+ // Always trace all of the info even if we cannot fit it in error log
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromGetI2CMasterTarget() - "
+ "i_i2cInfo.i2cMasterPath[%d].type = %.02X i_i2cInfo.i2cMasterPath[%d].instance = %.02X",
+ i, i_i2cInfo.i2cMasterPath[i].type, i, i_i2cInfo.i2cMasterPath[i].instance );
+
+ }
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_TARGET_NULL
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_GETI2CMASTERTARGET
+ * @userdata1[00:31] Attribute Chip Type Enum
+ * @userdata1[32:63] HUID of target
+ * @userdata2 Compressed Entity Path
+ * @devdesc I2C master path target is null.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_GETI2CMASTERTARGET,
+ EEPROM_TARGET_NULL,
+ TWO_UINT32_TO_UINT64(
+ i_i2cInfo.eepromRole,
+ TARGETING::get_huid(i_target) ),
+ l_epCompressed,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( EEPROM_COMP_NAME );
+
+ char* l_masterPath = i_i2cInfo.i2cMasterPath.toString();
+ ERRORLOG::ErrlUserDetailsString(l_masterPath).addToLog(err);
+ free(l_masterPath);
+ l_masterPath = nullptr;
+
+ break;
+ }
+
+ } while( 0 );
+
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromGetI2CMasterTarget()" );
+
+ return err;
+} // end eepromGetI2CMasterTarget
+
+
+/**
+ * @brief Compare predicate for EepromInfo_t
+ */
+class isSameEeprom
+{
+ public:
+ isSameEeprom( const EepromInfo_t& i_first )
+ : iv_first(i_first)
+ {}
+
+ bool operator()( const EepromInfo_t& i_second )
+ {
+ return( (iv_first.i2cMaster == i_second.i2cMaster)
+ && (iv_first.engine == i_second.engine)
+ && (iv_first.port == i_second.port)
+ && (iv_first.devAddr == i_second.devAddr) );
+ }
+ private:
+ const EepromInfo_t& iv_first;
+};
+
+/**
+ * @brief Add any new EEPROMs associated with this target
+ * to the list
+ * @param[in] i_list : list of previously discovered EEPROMs
+ * @param[out] i_targ : owner of EEPROMs to add
+ */
+void add_to_list( std::list<EepromInfo_t>& i_list,
+ TARGETING::Target* i_targ )
+{
+ TRACFCOMP(g_trac_eeprom,"Targ %.8X",TARGETING::get_huid(i_targ));
+
+ // try all defined types of EEPROMs
+ for( EEPROM_ROLE eep_type = FIRST_CHIP_TYPE;
+ eep_type < LAST_CHIP_TYPE;
+ eep_type = static_cast<EEPROM_ROLE>(eep_type+1) )
+ {
+ bool found_eep = false;
+ TARGETING::EepromVpdPrimaryInfo eepromData;
+
+ switch( eep_type )
+ {
+ case VPD_PRIMARY:
+ if( i_targ->
+ tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO>
+ ( eepromData ) )
+
+ {
+ found_eep = true;
+ }
+ break;
+
+ case VPD_BACKUP:
+ if( i_targ->
+ tryGetAttr<TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO>
+ ( reinterpret_cast<
+ TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO_type&>
+ ( eepromData) ) )
+ {
+ found_eep = true;
+ }
+ break;
+
+ case SBE_PRIMARY:
+ if( i_targ->
+ tryGetAttr<TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO>
+ ( reinterpret_cast<
+ TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO_type&>
+ ( eepromData) ) )
+ {
+ found_eep = true;
+ }
+ break;
+
+ case SBE_BACKUP:
+ if( i_targ->
+ tryGetAttr<TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO>
+ ( reinterpret_cast<
+ TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO_type&>
+ ( eepromData) ) )
+ {
+ found_eep = true;
+ }
+ break;
+
+ case LAST_CHIP_TYPE:
+ //only included to catch additional types later on
+ found_eep = false;
+ break;
+ }
+
+ if( !found_eep )
+ {
+ TRACDCOMP(g_trac_eeprom,"eep_type=%d not found",eep_type);
+ //nothing to do
+ continue;
+ }
+
+ // check that the path exists
+ bool exists = false;
+ TARGETING::targetService().exists( eepromData.i2cMasterPath,
+ exists );
+ if( !exists )
+ {
+ TRACDCOMP(g_trac_eeprom,"no master path");
+ continue;
+ }
+
+ // Since it exists, convert to a target
+ TARGETING::Target* i2cm = TARGETING::targetService()
+ .toTarget( eepromData.i2cMasterPath );
+ if( NULL == i2cm )
+ {
+ //not sure how this could happen, but just skip it
+ TRACDCOMP(g_trac_eeprom,"no target");
+ continue;
+ }
+
+ // ignore anything with junk data
+ TARGETING::Target * sys = NULL;
+ TARGETING::targetService().getTopLevelTarget( sys );
+ if( i2cm == sys )
+ {
+ TRACDCOMP(g_trac_eeprom,"sys target");
+ continue;
+ }
+
+ // copy all the data out
+ EepromInfo_t eep_info;
+ eep_info.i2cMaster = i2cm;
+ eep_info.engine = eepromData.engine;
+ eep_info.port = eepromData.port;
+ eep_info.devAddr = eepromData.devAddr;
+ eep_info.device = eep_type;
+ eep_info.assocTarg = i_targ;
+ eep_info.chipCount = eepromData.chipCount;
+ eep_info.sizeKB = eepromData.maxMemorySizeKB;
+ eep_info.addrBytes = eepromData.byteAddrOffset;
+ //one more lookup for the speed
+ TARGETING::ATTR_I2C_BUS_SPEED_ARRAY_type speeds;
+ if( i2cm->tryGetAttr<TARGETING::ATTR_I2C_BUS_SPEED_ARRAY>
+ (speeds) )
+ {
+ if( (eep_info.engine > I2C_BUS_MAX_ENGINE(speeds))
+ || (eep_info.port > I2C_BUS_MAX_PORT(speeds)) )
+ {
+ TRACDCOMP(g_trac_eeprom,"bad engine/port");
+ continue;
+ }
+ eep_info.busFreq = speeds[eep_info.engine][eep_info.port];
+ eep_info.busFreq *= 1000; //convert KHz->Hz
+ }
+ else
+ {
+ TRACDCOMP(g_trac_eeprom,"eep_type=%d, Speed=0",eep_type);
+ continue;
+ }
+
+ // check if the eeprom is already in our list
+ std::list<EepromInfo_t>::iterator oldeep =
+ find_if( i_list.begin(), i_list.end(),
+ isSameEeprom(eep_info) );
+ if( oldeep == i_list.end() )
+ {
+ // didn't find it in our list so stick it into the output list
+ i_list.push_back(eep_info);
+ TRACFCOMP(g_trac_eeprom,"--Adding i2cm=%.8X, type=%d, eng=%d, port=%d, addr=%.2X for %.8X", TARGETING::get_huid(i2cm),eep_type,eepromData.engine,eepromData.port, eep_info.devAddr, TARGETING::get_huid(eep_info.assocTarg));
+ }
+ else
+ {
+ TRACFCOMP(g_trac_eeprom,"--Skipping duplicate i2cm=%.8X, type=%d, eng=%d, port=%d, addr=%.2X for %.8X", TARGETING::get_huid(i2cm),eep_type,eepromData.engine,eepromData.port, eep_info.devAddr, TARGETING::get_huid(eep_info.assocTarg));
+ }
+ }
+}
+
+/**
+ * @brief Return a set of information related to every unique
+ * EEPROM in the system
+ */
+void getEEPROMs( std::list<EepromInfo_t>& o_info )
+{
+ TRACFCOMP(g_trac_eeprom,">>getEEPROMs()");
+
+ // We only want to have a single entry in our list per
+ // physical EEPROM. Since multiple targets could be
+ // using the same EEPROM, we need to have a hierarchy
+ // of importance.
+ // node/planar > proc > membuf > dimm
+
+ // predicate to only look for this that are actually there
+ TARGETING::PredicateHwas isPresent;
+ isPresent.reset().poweredOn(true).present(true);
+
+ // #1 - Nodes
+ TARGETING::PredicateCTM nodes( TARGETING::CLASS_ENC,
+ TARGETING::TYPE_NODE,
+ TARGETING::MODEL_NA );
+ TARGETING::PredicatePostfixExpr l_nodeFilter;
+ l_nodeFilter.push(&isPresent).push(&nodes).And();
+ TARGETING::TargetRangeFilter node_itr( TARGETING::targetService().begin(),
+ TARGETING::targetService().end(),
+ &l_nodeFilter );
+ for( ; node_itr; ++node_itr )
+ {
+ add_to_list( o_info, *node_itr );
+ }
+
+ // #2 - Procs
+ TARGETING::PredicateCTM procs( TARGETING::CLASS_CHIP,
+ TARGETING::TYPE_PROC,
+ TARGETING::MODEL_NA );
+ TARGETING::PredicatePostfixExpr l_procFilter;
+ l_procFilter.push(&isPresent).push(&procs).And();
+ TARGETING::TargetRangeFilter proc_itr( TARGETING::targetService().begin(),
+ TARGETING::targetService().end(),
+ &l_procFilter );
+ for( ; proc_itr; ++proc_itr )
+ {
+ add_to_list( o_info, *proc_itr );
+ }
+
+ // #3 - Membufs
+ TARGETING::PredicateCTM membs( TARGETING::CLASS_CHIP,
+ TARGETING::TYPE_MEMBUF,
+ TARGETING::MODEL_NA );
+ TARGETING::PredicatePostfixExpr l_membFilter;
+ l_membFilter.push(&isPresent).push(&membs).And();
+ TARGETING::TargetRangeFilter memb_itr( TARGETING::targetService().begin(),
+ TARGETING::targetService().end(),
+ &l_membFilter );
+ for( ; memb_itr; ++memb_itr )
+ {
+ add_to_list( o_info, *memb_itr );
+ }
+
+ // #4 - DIMMs
+ TARGETING::PredicateCTM dimms( TARGETING::CLASS_LOGICAL_CARD,
+ TARGETING::TYPE_DIMM,
+ TARGETING::MODEL_NA );
+ TARGETING::PredicatePostfixExpr l_dimmFilter;
+ l_dimmFilter.push(&isPresent).push(&dimms).And();
+ TARGETING::TargetRangeFilter dimm_itr( TARGETING::targetService().begin(),
+ TARGETING::targetService().end(),
+ &l_dimmFilter );
+ for( ; dimm_itr; ++dimm_itr )
+ {
+ #ifdef CONFIG_NVDIMM
+ // Skip if this is an NVDIMM as this will get added later
+ if (TARGETING::isNVDIMM( *dimm_itr ))
+ continue;
+ #endif
+ add_to_list( o_info, *dimm_itr );
+ }
+
+ TRACFCOMP(g_trac_eeprom,"<<getEEPROMs()");
+}
+
+} \ No newline at end of file
diff --git a/src/usr/i2c/eepromdd.C b/src/usr/i2c/eepromdd.C
index c14180a3a..7e56aa6b7 100755
--- a/src/usr/i2c/eepromdd.C
+++ b/src/usr/i2c/eepromdd.C
@@ -35,164 +35,108 @@
// ----------------------------------------------
// Includes
// ----------------------------------------------
-#include <string.h>
-#include <sys/time.h>
-#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/util.H>
-#include <devicefw/driverif.H>
-#include <i2c/eepromddreasoncodes.H>
-#include <i2c/eepromif.H>
-#include <i2c/i2creasoncodes.H>
-#include <i2c/i2cif.H>
-#include "eepromdd.H"
-#include "errlud_i2c.H"
+#include <errl/errlentry.H> // errlHndl_t
+#include <devicefw/driverif.H> // DeviceFW::OperationTyp
+ // TARGETING::Target
+ // va_list
+#include "eepromCache.H"
+#include "eepromdd_hardware.H"
-// ----------------------------------------------
-// Globals
-// ----------------------------------------------
-mutex_t g_eepromMutex = MUTEX_INITIALIZER;
-
-// ----------------------------------------------
-// Trace definitions
-// ----------------------------------------------
-trace_desc_t* g_trac_eeprom = NULL;
-TRAC_INIT( & g_trac_eeprom, EEPROM_COMP_NAME, KILOBYTE );
-
-trace_desc_t* g_trac_eepromr = NULL;
-TRAC_INIT( & g_trac_eepromr, "EEPROMR", KILOBYTE );
+extern trace_desc_t* g_trac_eeprom;
// Easy macro replace for unit testing
//#define TRACUCOMP(args...) TRACFCOMP(args)
#define TRACUCOMP(args...)
-// ----------------------------------------------
-// Defines
-// ----------------------------------------------
-#define MAX_BYTE_ADDR 2
-#define EEPROM_MAX_RETRIES 2
-// ----------------------------------------------
-
-
-namespace
-{
-
-// ------------------------------------------------------------------
-// errorIsRetryable
-// ------------------------------------------------------------------
-static bool errorIsRetryable(uint16_t reasonCode)
-{
- return reasonCode == I2C::I2C_NACK_ONLY_FOUND ||
- reasonCode == I2C::I2C_ARBITRATION_LOST_ONLY_FOUND;
-}
-
-}
-
namespace EEPROM
{
-// Register the perform Op with the routing code for Procs.
-DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
- DeviceFW::EEPROM,
- TARGETING::TYPE_PROC,
- eepromPerformOp );
-
-// Register the perform Op with the routing code for DIMMs.
-DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
- DeviceFW::EEPROM,
- TARGETING::TYPE_DIMM,
- eepromPerformOp );
-
-// Register the perform Op with the routing code for Memory Buffers.
-DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
- DeviceFW::EEPROM,
- TARGETING::TYPE_MEMBUF,
- eepromPerformOp );
-
-// Register the perform Op with the routing code for Nodes.
-DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
- DeviceFW::EEPROM,
- TARGETING::TYPE_NODE,
- eepromPerformOp );
-
-// Register the perform Op with the routing code for MCS chiplets.
-DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
- DeviceFW::EEPROM,
- TARGETING::TYPE_MCS,
- eepromPerformOp );
-
-// Register the perform Op with the routing code for Open-Capi Memory Buffer Chips.
-DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
- DeviceFW::EEPROM,
- TARGETING::TYPE_OCMB_CHIP,
- eepromPerformOp );
-
-
-/**
- *
- * @brief A useful utility to dump (trace out) the EepromVpdPrimaryInfo data.
- * Use as needed.
- *
- * @param [in] i_i2cInfo - The EepromVpdPrimaryInfo data to dump for user
- *
- */
-void dumpEepromData(const TARGETING::EepromVpdPrimaryInfo & i_i2cInfo)
-{
- TRACFCOMP (g_trac_eeprom, INFO_MRK"EepromVpdPrimaryInfo data: "
- "engine=%d, port=%d, devAddr=0X%X, writePageSize=%d, "
- "maxMemorySizeKB=0x%X, chipCount=%d, writeCycleTime=%d",
- i_i2cInfo.engine, i_i2cInfo.port, i_i2cInfo.devAddr,
- i_i2cInfo.writePageSize, i_i2cInfo.maxMemorySizeKB,
- i_i2cInfo.chipCount, i_i2cInfo.writeCycleTime);
-
- char* l_masterPath = i_i2cInfo.i2cMasterPath.toString();
- char* l_muxPath = i_i2cInfo.i2cMuxPath.toString();
- TRACFCOMP (g_trac_eeprom, INFO_MRK"EepromVpdPrimaryInfo data cont.: "
- "masterPath=%s, muxSelector=0x%X, muxPath=%s",
- l_masterPath, i_i2cInfo.i2cMuxBusSelector, l_muxPath);
-
- free(l_masterPath);
- free(l_muxPath);
- l_masterPath = l_muxPath = nullptr;
-}
-
+#ifdef CONFIG_SUPPORT_EEPROM_CACHING
/**
- *
- * @brief A useful utility to dump (trace out) the eeprom_addr_t data.
- * Use as needed.
- *
- * @param [in] i_i2cInfo - The eeprom_addr_t data to dump for user
- *
- */
-void dumpEepromData(const eeprom_addr_t & i_i2cInfo)
-{
- TRACFCOMP (g_trac_eeprom, INFO_MRK"eeprom_addr_t data: \n"
- "engine=%d, port=%d, devAddr=0X%X, writePageSize=%d, \n"
- "devSize_KB=0x%X, chipCount=%d, writeCycleTime=%d \n",
- i_i2cInfo.engine, i_i2cInfo.port, i_i2cInfo.devAddr,
- i_i2cInfo.writePageSize, i_i2cInfo.devSize_KB,
- i_i2cInfo.chipCount, i_i2cInfo.writeCycleTime);
-
- char* l_masterPath = i_i2cInfo.i2cMasterPath.toString();
- char* l_muxPath = i_i2cInfo.i2cMuxPath.toString();
- TRACFCOMP (g_trac_eeprom, INFO_MRK"eeprom_addr_t data cont.: \n"
- "masterPath=%s, muxSelector=0x%X, muxPath=%s \n",
- l_masterPath, i_i2cInfo.i2cMuxBusSelector, l_muxPath);
+*
+* @brief Determine if a given EEPROM has been cached into pnor's EECACHE
+* section yet or not. If it has source will be CACHE, if it has not
+* been cached yet, then source will be HARDWARE
+*
+*
+* @param[in] i_target - Target device associated with the eeprom.
+*
+* @param[in/out] io_i2cInfo - Struct containing information that tells us which
+* EEPROM associated with the given Target we wish
+* to lookup. NOTE it is assumed eepromRole member
+* in this struct has been filled out prior to it
+* being passed to this function.
+*
+* @pre i_i2cInfo.eepromRole is expected to have a valid value set
+*
+* @post o_source will either be EEPROM::CACHE or EEPROM::HARDWARE
+* io_i2cInfo will have info filled out (side effect not used)
+*
+* @return errlHndl_t - NULL if successful, otherwise a pointer to the
+* error log.
+*
+*/
+errlHndl_t resolveSource(TARGETING::Target * i_target,
+ eeprom_addr_t & io_i2cInfo,
+ EEPROM::EEPROM_SOURCE & o_source)
+{
+ eepromRecordHeader l_eepromRecordHeader;
+ errlHndl_t err = nullptr;
+
+ err = buildEepromRecordHeader(i_target,
+ io_i2cInfo,
+ l_eepromRecordHeader);
+ // if lookupEepromAddr returns non-zero address
+ // then we know it exists in cache somewhere
+ if(lookupEepromAddr(l_eepromRecordHeader))
+ {
+ o_source = EEPROM::CACHE;
+ }
+ else
+ {
+ o_source = EEPROM::HARDWARE;
+ }
- free(l_masterPath);
- free(l_muxPath);
- l_masterPath = l_muxPath = nullptr;
+ return err;
}
+#endif // CONFIG_SUPPORT_EEPROM_CACHING
// ------------------------------------------------------------------
// eepromPerformOp
// ------------------------------------------------------------------
+/**
+*
+* @brief Perform an EEPROM access operation.
+*
+* @param[in] i_opType - Operation Type - See DeviceFW::OperationType in
+* driververif.H
+*
+* @param[in] i_target - Target device.
+*
+* @param[in/out] io_buffer
+* INPUT: Pointer to the data that will be written to the target
+* device.
+* OUTPUT: Pointer to the data that was read from the target device.
+*
+* @param[in/out] io_buflen
+* INPUT: Length of the buffer to be written to target device.
+* OUTPUT: Length of buffer that was written, or length of buffer
+* to be read from target device.
+*
+* @param [in] i_accessType - Access Type - See DeviceFW::AccessType in
+* usrif.H
+*
+* @param [in] i_args - This is an argument list for the device driver
+* framework. This argument list consists of the chip number of
+* the EEPROM to access from the given I2C Master target and the
+* internal offset to use on the slave I2C device.
+*
+* @return errlHndl_t - NULL if successful, otherwise a pointer to the
+* error log.
+*
+*/
errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
TARGETING::Target * i_target,
void * io_buffer,
@@ -200,2006 +144,109 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
int64_t i_accessType,
va_list i_args )
{
- errlHndl_t err = NULL;
- TARGETING::Target * i2cMasterTarget = NULL;
+ errlHndl_t err = nullptr;
eeprom_addr_t i2cInfo;
i2cInfo.eepromRole = va_arg( i_args, uint64_t );
- i2cInfo.offset = va_arg( i_args, uint64_t );
-
+ i2cInfo.offset = va_arg( i_args, uint64_t );
+ #ifdef CONFIG_SUPPORT_EEPROM_CACHING
+ EEPROM_SOURCE l_source = (EEPROM_SOURCE)va_arg(i_args, uint64_t);
+ #endif
TRACDCOMP( g_trac_eeprom,
ENTER_MRK"eepromPerformOp()" );
TRACUCOMP (g_trac_eeprom, ENTER_MRK"eepromPerformOp(): "
"i_opType=%d, chip=%d, offset=%x, len=%d",
(uint64_t) i_opType, i2cInfo.eepromRole, i2cInfo.offset, io_buflen);
+ do{
-#ifdef __HOSTBOOT_RUNTIME
- // At runtime the OCC sensor cache will need to be diabled to avoid I2C
- // collisions. This bool indicates the sensor cache was enabled but is
- // now disabled and needs to be re-enabled when the eeprom op completes.
- bool scacDisabled = false;
-#endif //__HOSTBOOT_RUNTIME
-
- void * l_pBuffer = io_buffer;
- size_t l_currentOpLen = io_buflen;
- size_t l_remainingOpLen = io_buflen;
-
- do
- {
- // Read Attributes needed to complete the operation
- err = eepromReadAttributes( i_target,
- i2cInfo );
-
- if( err )
+ #ifdef CONFIG_SUPPORT_EEPROM_CACHING
+ if(l_source == EEPROM::AUTOSELECT)
{
- break;
+ err = resolveSource(i_target, i2cInfo, l_source);
}
- size_t l_snglChipSize = (i2cInfo.devSize_KB * KILOBYTE)
- / i2cInfo.chipCount;
-
- // Check to see if we need to find a new target for
- // the I2C Master
- err = eepromGetI2CMasterTarget( i_target,
- i2cInfo,
- i2cMasterTarget );
-
- if( err )
- {
- break;
- }
-
- // Check that the offset + data length is less than device max size
- if ( ( i2cInfo.offset + io_buflen ) >
- ( i2cInfo.devSize_KB * KILOBYTE ) )
+ if(err)
{
TRACFCOMP( g_trac_eeprom,
- ERR_MRK"eepromPerformOp(): Device Overflow! "
- "C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X "
- "devSizeKB=0x%X", i2cInfo.eepromRole, i2cInfo.engine,
- i2cInfo.port, i2cInfo.devAddr, i2cInfo.offset,
- io_buflen, i2cInfo.devSize_KB);
-
-
- /*@
- * @errortype
- * @reasoncode EEPROM_OVERFLOW_ERROR
- * @severity ERRL_SEV_UNRECOVERABLE
- * @moduleid EEPROM_PERFORM_OP
- * @userdata1[0:31] Offset
- * @userdata1[32:63] Buffer Length
- * @userdata2 Device Max Size (in KB)
- * @devdesc I2C Buffer Length + Offset > Max Size
- * @custdesc A problem occurred during the IPL of the
- * system: I2C buffer offset is too large.
- */
- err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_PERFORM_OP,
- EEPROM_OVERFLOW_ERROR,
- TWO_UINT32_TO_UINT64(
- i2cInfo.offset,
- io_buflen ),
- i2cInfo.devSize_KB,
- true /*Add HB SW Callout*/ );
-
- err->collectTrace( EEPROM_COMP_NAME );
-
+ "eepromPerformOp() An error occured trying to resolve what source to perform op on (CACHE or HARDWARE)");
break;
}
- // Adjust offset and devAddr to the correct starting chip
- while( i2cInfo.offset >= l_snglChipSize )
- {
- i2cInfo.offset -= l_snglChipSize;
- i2cInfo.devAddr += EEPROM_DEVADDR_INC;
- }
-
- // Keep first op length within a chip
- if( ( i2cInfo.offset + io_buflen ) > l_snglChipSize )
+ if(l_source == EEPROM::CACHE )
{
- l_currentOpLen = l_snglChipSize - i2cInfo.offset;
- }
-
- TRACFCOMP( g_trac_eeprom,
- "eepromPerformOp(): i_opType=%d "
- "C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X, ",
- i_opType, i2cInfo.eepromRole, i2cInfo.engine,
- i2cInfo.port, i2cInfo.devAddr, i2cInfo.offset, io_buflen)
-
- TRACFCOMP (g_trac_eeprom,
- "eepromPerformOp(): snglChipKB=0x%X, chipCount=0x%X, devSizeKB=0x%X",
- l_snglChipSize, i2cInfo.chipCount, i2cInfo.devSize_KB);
-
- // Printing mux info separately, if combined, nothing is displayed
- char* l_muxPath = i2cInfo.i2cMuxPath.toString();
- TRACFCOMP(g_trac_eeprom, "eepromPerformOp(): "
- "muxSelector=0x%X, muxPath=%s",
- i2cInfo.i2cMuxBusSelector,
- l_muxPath);
- free(l_muxPath);
- l_muxPath = nullptr;
+ // Read the copy of the EEPROM data we have cached in PNOR
+ err = eepromPerformOpCache(i_opType, i_target, io_buffer, io_buflen, i2cInfo);
-#ifdef __HOSTBOOT_RUNTIME
- // Disable Sensor Cache if the I2C master target is MEMBUF
- if( i2cMasterTarget->getAttr<TARGETING::ATTR_TYPE>() ==
- TARGETING::TYPE_MEMBUF )
- {
- err = I2C::i2cDisableSensorCache(i2cMasterTarget,scacDisabled);
- if ( err )
- {
- break;
- }
- }
-#endif //__HOSTBOOT_RUNTIME
-
- // Do the read or write
- while(l_remainingOpLen > 0)
- {
- if( i_opType == DeviceFW::READ )
- {
- err = eepromRead( i2cMasterTarget,
- l_pBuffer,
- l_currentOpLen,
- i2cInfo );
- }
- else if( i_opType == DeviceFW::WRITE )
- {
- err = eepromWrite( i2cMasterTarget,
- l_pBuffer,
- l_currentOpLen,
- i2cInfo );
- }
- else
- {
- TRACFCOMP( g_trac_eeprom,
- ERR_MRK"eepromPerformOp(): "
- "Invalid EEPROM Operation!");
-
- /*@
- * @errortype
- * @reasoncode EEPROM_INVALID_OPERATION
- * @severity ERRL_SEV_UNRECOVERABLE
- * @moduleid EEPROM_PERFORM_OP
- * @userdata1 Operation Type
- * @userdata2 Chip to Access
- * @devdesc Invalid operation type.
- */
- err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_PERFORM_OP,
- EEPROM_INVALID_OPERATION,
- i_opType,
- i2cInfo.eepromRole,
- true /*Add HB SW Callout*/ );
-
- err->collectTrace( EEPROM_COMP_NAME );
- }
-
- if ( err )
+ if(err)
{
break;
}
- // Adjust the buffer pointer and remaining op length
- l_pBuffer = (void *)(reinterpret_cast<uint64_t>(l_pBuffer)
- + l_currentOpLen);
- l_remainingOpLen -= l_currentOpLen;
-
- if( l_remainingOpLen > l_snglChipSize )
+ // If the operation is a write we also need to "write through" to HW after
+ // we write cache
+ if(i_opType == DeviceFW::WRITE)
{
- // Keep next op length within a chip
- l_currentOpLen = l_snglChipSize;
+ err = eepromPerformOpHW(i_opType, i_target, io_buffer, io_buflen, i2cInfo);
}
- else if( l_remainingOpLen > 0 )
- {
- // Set next op length to what is left to do
- l_currentOpLen = l_remainingOpLen;
- }
- else
- {
- // Break if there is nothing left to do
- break;
- }
-
- // Prepare the address at the start of next EEPROM
- i2cInfo.offset = 0;
- i2cInfo.devAddr += EEPROM_DEVADDR_INC;
- } // Do the read or write
- } while( 0 );
-
-#ifdef __HOSTBOOT_RUNTIME
- // Re-enable sensor cache if it was disabled before the eeprom op and
- // the I2C master target is MEMBUF
- if( scacDisabled &&
- (i2cMasterTarget->getAttr<TARGETING::ATTR_TYPE>() == TARGETING::TYPE_MEMBUF) )
- {
- errlHndl_t tmp_err = NULL;
-
- tmp_err = I2C::i2cEnableSensorCache(i2cMasterTarget);
-
- if( err && tmp_err)
- {
- delete tmp_err;
- TRACFCOMP(g_trac_eeprom,
- ERR_MRK" Enable Sensor Cache failed for HUID=0x%.8X",
- TARGETING::get_huid(i2cMasterTarget));
- }
- else if(tmp_err)
- {
- err = tmp_err;
- }
- }
-#endif //__HOSTBOOT_RUNTIME
-
- // If there is an error, add parameter info to log
- if ( err != NULL )
- {
- EEPROM::UdEepromParms( i_opType,
- i_target,
- io_buflen,
- i2cInfo )
- .addToLog(err);
- }
-
- TRACDCOMP( g_trac_eeprom,
- EXIT_MRK"eepromPerformOp() - %s",
- ((NULL == err) ? "No Error" : "With Error") );
-
- return err;
-} // end eepromPerformOp
-
-#ifndef __HOSTBOOT_RUNTIME
-//-------------------------------------------------------------------
-//eepromPresence
-//-------------------------------------------------------------------
-bool eepromPresence ( TARGETING::Target * i_target )
-{
- TRACUCOMP(g_trac_eeprom, ENTER_MRK"eepromPresence()");
-
- errlHndl_t err = NULL;
- bool l_present = false;
- TARGETING::Target * i2cMasterTarget = NULL;
-
- eeprom_addr_t i2cInfo;
-
- i2cInfo.eepromRole = EEPROM::VPD_PRIMARY;
- i2cInfo.offset = 0;
- do
- {
-
- // Read Attributes needed to complete the operation
- err = eepromReadAttributes( i_target,
- i2cInfo );
-
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- ERR_MRK"Error in eepromPresence::eepromReadAttributes()");
- break;
}
-
- // Check to see if we need to find a new target for
- // the I2C Master
- err = eepromGetI2CMasterTarget( i_target,
- i2cInfo,
- i2cMasterTarget );
-
- if( err )
+ else if(l_source == EEPROM::HARDWARE)
{
- TRACFCOMP(g_trac_eeprom,
- ERR_MRK"Error in eepromPresence::eepromGetI2Cmaster()");
- break;
+ // Read from the actual physical EEPROM device
+ err = eepromPerformOpHW(i_opType, i_target, io_buffer, io_buflen, i2cInfo);
}
+ #else
- //Check for the target at the I2C level
- l_present = I2C::i2cPresence(i2cMasterTarget,
- i2cInfo.port,
- i2cInfo.engine,
- i2cInfo.devAddr,
- i2cInfo.i2cMuxBusSelector,
- i2cInfo.i2cMuxPath);
+ // Read from the actual physical EEPROM device
+ err = eepromPerformOpHW(i_opType, i_target, io_buffer, io_buflen, i2cInfo);
- if( !l_present )
- {
- TRACDCOMP(g_trac_eeprom,
- ERR_MRK"i2cPresence returned false! chip NOT present!");
- break;
- }
+ #endif // CONFIG_SUPPORT_EEPROM_CACHING
- } while( 0 );
- // If there was an error commit the error log
- if( err )
- {
- errlCommit( err, I2C_COMP_ID );
- }
-
- TRACDCOMP(g_trac_eeprom, EXIT_MRK"eepromPresence()");
- return l_present;
-}
-#endif
-
-
-
-// ------------------------------------------------------------------
-// eepromPageOp
-// ------------------------------------------------------------------
-errlHndl_t eepromPageOp( TARGETING::Target * i_target,
- bool i_switchPage,
- bool i_lockMutex,
- bool & io_pageLocked,
- uint8_t i_desiredPage,
- eeprom_addr_t i_i2cInfo )
-{
- TRACUCOMP(g_trac_eeprom,
- ENTER_MRK"eepromPageOp()");
-
- errlHndl_t l_err = NULL;
- size_t l_placeHolderZero = 0;
-
- do
- {
- // DDR4 requires EEPROM page to be selected before read/write operation.
- // The following operation locks the EEPROM_PAGE attribute behind a
- // mutex and switches all DIMMs on the I2C bus to the appropriate
- // page.
- if( i_i2cInfo.addrSize == ONE_BYTE_ADDR_PAGESELECT )
- {
-
- bool l_lockPage;
- if( i_switchPage )
- {
- // we want to switch to the desired page
- l_lockPage = true;
- l_err = deviceOp( DeviceFW::WRITE,
- i_target,
- NULL,
- l_placeHolderZero,
- DEVICE_I2C_CONTROL_PAGE_OP(
- i_i2cInfo.port,
- i_i2cInfo.engine,
- l_lockPage,
- i_desiredPage,
- i_lockMutex ));
-
- if( l_err )
- {
- TRACFCOMP(g_trac_eeprom,
- "eepromPageOp::Failed locking EEPROM page");
- break;
- }
- // if we make it this far, we successfully locked the page mutex
- io_pageLocked = true;
- }
- else
- {
- // we only want to unlock the page
- l_lockPage = false;
- l_err = deviceOp( DeviceFW::WRITE,
- i_target,
- NULL,
- l_placeHolderZero,
- DEVICE_I2C_CONTROL_PAGE_OP(
- i_i2cInfo.port,
- i_i2cInfo.engine,
- l_lockPage,
- l_placeHolderZero,
- i_lockMutex ));
-
- if( l_err )
- {
- TRACFCOMP( g_trac_eeprom,
- "eepromPageOp()::failed unlocking EEPROM page");
- break;
- }
- // if we make it this far, we successfully unlocked the page
- io_pageLocked = false;
- }
- }
}while(0);
- TRACUCOMP(g_trac_eeprom,
- EXIT_MRK"eepromPageOp()");
- return l_err;
-}
-
-
-// ------------------------------------------------------------------
-// crossesEepromPageBoundary
-// ------------------------------------------------------------------
-bool crossesEepromPageBoundary( uint64_t i_originalOffset,
- size_t i_originalLen,
- size_t & io_newLen,
- size_t & o_pageTwoBuflen,
- eeprom_addr_t i_i2cInfo )
-{
- bool l_boundaryCrossed = false;
- size_t l_higherBound = i_originalOffset + i_originalLen;
-
- if( ( i_i2cInfo.addrSize == ONE_BYTE_ADDR_PAGESELECT ) &&
- ( ( i_originalOffset < EEPROM_PAGE_SIZE ) &&
- ( l_higherBound > EEPROM_PAGE_SIZE) ) )
- {
- // The read/write request crosses the boundary
- l_boundaryCrossed = true;
-
- // Calculate the new length of the page 0 buffer and the
- // length of the page 1 buffer
- o_pageTwoBuflen = l_higherBound - EEPROM_PAGE_SIZE;
- io_newLen = i_originalLen - o_pageTwoBuflen;
- }
- else
- {
- // The read/write request does not cross the boundary.
- // Update new length to be used by subsequent operations
- io_newLen = i_originalLen;
- o_pageTwoBuflen = 0;
- }
-
- return l_boundaryCrossed;
-}
-
-
-
-// ------------------------------------------------------------------
-// eepromRead
-// ------------------------------------------------------------------
-errlHndl_t eepromRead ( TARGETING::Target * i_target,
- void * o_buffer,
- size_t i_buflen,
- eeprom_addr_t i_i2cInfo )
-{
- errlHndl_t err = NULL;
- uint8_t byteAddr[MAX_BYTE_ADDR];
- size_t byteAddrSize = 0;
- bool l_pageLocked = false;
- uint8_t l_desiredPage = 0;
- bool l_boundaryCrossed = false;
- size_t l_readBuflen = 0;
- size_t l_pageTwoBuflen = 0;
-
- TRACUCOMP( g_trac_eeprom,
- ENTER_MRK"eepromRead()" );
-
- do
- {
- TRACUCOMP( g_trac_eepromr,
- "EEPROM READ START : Chip: %02d : Offset %.2X : Len %d",
- i_i2cInfo.chip, i_i2cInfo.offset, i_buflen );
-
- // At maximum we want to do 1 KB reads at a time. The largest that
- // the scom byte range will support is 64 KB - 1 but we will do 1
- // KB at a time to catch fails faster. This is useful when we do big
- // reads when caching the eeprom to pnor.
- size_t l_readLenRemaining = i_buflen;
- size_t l_currentReadLen;
-
- // Lock to sequence operations
- mutex_lock( &g_eepromMutex );
-
- while( l_readLenRemaining > 0 )
- {
- l_currentReadLen = l_readLenRemaining < KILOBYTE ? l_readLenRemaining : KILOBYTE;
-
- // Check to see if the Read operation straddles the EEPROM page
- // boundary.Note this is only required for systems w/ DDR4 industry
- // standard dimms. DDR4 ISDIMMS have a max of 512 bytes so we will
- // never loop through this multiple times on those systems
- l_boundaryCrossed = crossesEepromPageBoundary( i_i2cInfo.offset,
- l_currentReadLen,
- l_readBuflen,
- l_pageTwoBuflen,
- i_i2cInfo );
-
- // Set addressing parameters
- err = eepromPrepareAddress( i_target,
- &byteAddr,
- byteAddrSize,
- l_desiredPage,
- i_i2cInfo);
-
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- ERR_MRK"eepromRead()::eepromPrepareAddress()");
- break;
- }
-
-
- // Attempt to lock page mutex
- // (only important in DDR4 IS-DIMM systems)
- bool l_switchPage = true;
- bool l_lockMutex = true;
- err = eepromPageOp( i_target,
- l_switchPage,
- l_lockMutex,
- l_pageLocked,
- l_desiredPage,
- i_i2cInfo );
-
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- "eepromRead()::eepromPageOp()::failed locking page");
- break;
- }
-
- // First Read. If Second read is necessary, this call will read
- // everything from the original offset up to the 256th byte
- err = eepromReadData( i_target,
- &(reinterpret_cast<uint8_t*>(o_buffer)[i_buflen - l_readLenRemaining]),
- l_readBuflen,
- &byteAddr,
- byteAddrSize,
- i_i2cInfo );
-
- i_i2cInfo.offset += l_currentReadLen;
- l_readLenRemaining -= l_currentReadLen;
-
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- "Failed reading data: original read");
- break;
- }
-
-
- // Perform the second Read if necessary. Read starts at
- // begining of EEPROM page 1 (offset=0x100) and reads the
- // rest of the required data.
- if( l_boundaryCrossed )
- {
- //Prepare the address to read at the start of EEPROM page one
- i_i2cInfo.offset = EEPROM_PAGE_SIZE; // 0x100
- err = eepromPrepareAddress( i_target,
- &byteAddr,
- byteAddrSize,
- l_desiredPage,
- i_i2cInfo );
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- "Error preparing address: second eeprom read");
- break;
- }
-
- // Switch to the second EEPROM page
- l_switchPage = true;
- l_lockMutex = false;
- err = eepromPageOp( i_target,
- l_switchPage,
- l_lockMutex,
- l_pageLocked,
- l_desiredPage,
- i_i2cInfo );
-
- if( err )
- {
- TRACFCOMP( g_trac_eeprom,
- "Failed switching to EEPROM page 1 for second read op");
- break;
- }
-
- // Perform the second read operation
- err = eepromReadData(
- i_target,
- &(reinterpret_cast<uint8_t*>(o_buffer)[l_readBuflen]),
- l_pageTwoBuflen,
- &byteAddr,
- byteAddrSize,
- i_i2cInfo );
-
- if( err )
- {
- TRACFCOMP( g_trac_eeprom,
- "Failed reading data: second read");
- break;
- }
- }
- }
-
-
- TRACUCOMP( g_trac_eepromr,
- "EEPROM READ END : Eeprom Role: %02d : Offset %.2X : Len %d : %016llx",
- i_i2cInfo.eepromRole, i_i2cInfo.offset, i_buflen,
- *((uint64_t*)o_buffer) );
-
- } while( 0 );
-
- // Unlock eeprom mutex no matter what
- mutex_unlock( & g_eepromMutex );
-
- // Whether we failed in the main routine or not, unlock page iff the page is locked
- if( l_pageLocked )
- {
- errlHndl_t l_pageOpErrl = NULL;
- bool l_switchPage = false;
- bool l_lockMutex = false;
- l_pageOpErrl = eepromPageOp( i_target,
- l_switchPage,
- l_lockMutex,
- l_pageLocked,
- l_desiredPage,
- i_i2cInfo );
- if( l_pageOpErrl )
- {
- TRACFCOMP(g_trac_eeprom,
- "eepromRead()::Failed unlocking page");
- errlCommit(l_pageOpErrl, I2C_COMP_ID);
- }
-
- }
-
- TRACUCOMP( g_trac_eeprom,
- EXIT_MRK"eepromRead()" );
-
- return err;
-} // end eepromRead
-
-
-// ------------------------------------------------------------------
-// eepromReadData
-// ------------------------------------------------------------------
-errlHndl_t eepromReadData( TARGETING::Target * i_target,
- void * o_buffer,
- size_t i_buflen,
- void * i_byteAddress,
- size_t i_byteAddressSize,
- eeprom_addr_t i_i2cInfo )
-{
- errlHndl_t l_err = NULL;
- errlHndl_t err_retryable = NULL;
-
- TRACUCOMP(g_trac_eeprom,
- ENTER_MRK"eepromReadData()");
- do
- {
- /************************************************************/
- /* Attempt read multiple times ONLY on retryable fails */
- /************************************************************/
- for (uint8_t retry = 0;
- retry <= EEPROM_MAX_RETRIES;
- retry++)
- {
-
- // Only write the byte address if we have data to write
- if( 0 != i_byteAddressSize )
- {
- // Use the I2C MUX OFFSET Interface for the READ
- l_err = deviceOp( DeviceFW::READ,
- i_target,
- o_buffer,
- i_buflen,
- DEVICE_I2C_ADDRESS_OFFSET(
- i_i2cInfo.port,
- i_i2cInfo.engine,
- i_i2cInfo.devAddr,
- i_byteAddressSize,
- reinterpret_cast<uint8_t*>(i_byteAddress),
- i_i2cInfo.i2cMuxBusSelector,
- &(i_i2cInfo.i2cMuxPath)));
-
- if( l_err )
- {
- TRACFCOMP(g_trac_eeprom,
- ERR_MRK"eepromReadData(): I2C Read-Offset failed on "
- "%d/%d/0x%X aS=%d",
- i_i2cInfo.port, i_i2cInfo.engine,
- i_i2cInfo.devAddr, i_byteAddressSize);
- TRACFBIN(g_trac_eeprom, "i_byteAddress[]",
- i_byteAddress, i_byteAddressSize);
-
- // Don't break here -- error handled below
- }
- }
- else
- {
- // Do the actual read via I2C
- l_err = deviceOp( DeviceFW::READ,
- i_target,
- o_buffer,
- i_buflen,
- DEVICE_I2C_ADDRESS(
- i_i2cInfo.port,
- i_i2cInfo.engine,
- i_i2cInfo.devAddr,
- i_i2cInfo.i2cMuxBusSelector,
- &(i_i2cInfo.i2cMuxPath) ) );
-
- if( l_err )
- {
- TRACFCOMP(g_trac_eeprom,
- ERR_MRK"eepromReadData(): I2C Read failed on "
- "%d/%d/0x%0X", i_i2cInfo.port, i_i2cInfo.engine,
- i_i2cInfo.devAddr);
-
- // Don't break here -- error handled below
- }
- }
-
- if ( l_err == NULL )
- {
- // Operation completed successfully
- // break from retry loop
- break;
- }
- else if ( !errorIsRetryable( l_err->reasonCode() ) )
- {
- // Only retry on errorIsRetryable() failures: break from retry loop
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): 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(EEPROM_COMP_NAME);
-
- // break from retry loop
- break;
- }
- else // Handle retryable error
- {
- // If op will be attempted again: save log and continue
- if ( retry < EEPROM_MAX_RETRIES )
- {
- // Only save original retryable error
- if ( err_retryable == NULL )
- {
- // Save original retryable error
- err_retryable = l_err;
-
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): "
- "Retryable Error rc=0x%X, eid=0x%X, tgt=0x%X, "
- "retry/MAX=%d/%d. Save error and retry",
- err_retryable->reasonCode(),
- err_retryable->eid(),
- TARGETING::get_huid(i_target),
- retry, EEPROM_MAX_RETRIES);
-
- err_retryable->collectTrace(EEPROM_COMP_NAME);
- }
- else
- {
- // Add data to original retryable error
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): "
- "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, EEPROM_MAX_RETRIES);
-
- ERRORLOG::ErrlUserDetailsString(
- "Another Retryable ERROR found")
- .addToLog(err_retryable);
-
- // Delete this new retryable error
- delete l_err;
- l_err = NULL;
- }
-
- // continue to retry
- continue;
- }
- else // no more retries: trace and break
- {
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): "
- "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, EEPROM_MAX_RETRIES);
-
- l_err->collectTrace(EEPROM_COMP_NAME);
-
- // break from retry loop
- break;
- }
- }
-
- } // end of retry loop
-
- // Handle saved retryable error, if any
- if (err_retryable)
- {
- if (l_err)
- {
- // commit original retryable error with new err PLID
- err_retryable->plid(l_err->plid());
- TRACFCOMP(g_trac_eeprom, "eepromReadData(): Committing saved retryable "
- "l_err eid=0x%X with plid of returned err: 0x%X",
- err_retryable->eid(), err_retryable->plid());
-
- ERRORLOG::ErrlUserDetailsTarget(i_target)
- .addToLog(err_retryable);
-
- errlCommit(err_retryable, EEPROM_COMP_ID);
- }
- else
- {
- // Since we eventually succeeded, delete original retryable error
- TRACFCOMP(g_trac_eeprom, "eepromReadData(): Op successful, "
- "deleting saved retryable err eid=0x%X, plid=0x%X",
- err_retryable->eid(), err_retryable->plid());
-
- delete err_retryable;
- err_retryable = NULL;
- }
- }
-
- }while( 0 );
-
- TRACUCOMP(g_trac_eeprom,
- EXIT_MRK"eepromReadData");
- return l_err;
-}
-
-
-
-// ------------------------------------------------------------------
-// eepromWrite
-// ------------------------------------------------------------------
-errlHndl_t eepromWrite ( TARGETING::Target * i_target,
- void * io_buffer,
- size_t & io_buflen,
- eeprom_addr_t i_i2cInfo )
-{
- errlHndl_t err = NULL;
- uint8_t l_desiredPage = 0;
- uint8_t l_originalPage = 0;
- uint8_t byteAddr[MAX_BYTE_ADDR];
- size_t byteAddrSize = 0;
- uint8_t * newBuffer = NULL;
- bool needFree = false;
- bool unlock = false;
- bool l_pageLocked = false;
- uint32_t data_left = 0;
- uint32_t diff_wps = 0;
- size_t l_writeBuflen = 0;
- size_t l_bytesIntoSecondPage = 0;
-
- TRACDCOMP( g_trac_eeprom,
- ENTER_MRK"eepromWrite()" );
-
- do
- {
- TRACUCOMP( g_trac_eeprom,
- "EEPROM WRITE START : Eeprom Role : %02d : Offset %.2X : Len %d : %016llx",
- i_i2cInfo.eepromRole, i_i2cInfo.offset, io_buflen,
- *((uint64_t*)io_buffer) );
-
-
- // Prepare address parameters
- err = eepromPrepareAddress( i_target,
- &byteAddr,
- byteAddrSize,
- l_desiredPage,
- i_i2cInfo);
-
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- ERR_MRK"eepromWrite()::eepromPrepareAddress()");
- break;
- }
-
- // Save original Page
- l_originalPage = l_desiredPage;
- // Attempt to lock page mutex
- bool l_switchPage = true; // true: Lock and switch page
- // false: Just unlock page
- bool l_lockMutex = true; // true: Lock mutex
- // false: Skip locking mutex step
- err = eepromPageOp( i_target,
- l_switchPage,
- l_lockMutex,
- l_pageLocked,
- l_desiredPage,
- i_i2cInfo );
-
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- "eepromWrite()::Failed locking EEPROM page");
- break;
- }
-
- // Check for writePageSize of zero
- if ( i_i2cInfo.writePageSize == 0 )
- {
- TRACFCOMP( g_trac_eeprom,
- ERR_MRK"eepromWrite(): writePageSize is 0!");
-
- /*@
- * @errortype
- * @reasoncode EEPROM_I2C_WRITE_PAGE_SIZE_ZERO
- * @severity ERRL_SEV_UNRECOVERABLE
- * @moduleid EEPROM_WRITE
- * @userdata1 HUID of target
- * @userdata2 Chip to Access
- * @devdesc I2C write page size is zero.
- */
- err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_WRITE,
- EEPROM_I2C_WRITE_PAGE_SIZE_ZERO,
- TARGETING::get_huid(i_target),
- i_i2cInfo.eepromRole,
- true /*Add HB SW Callout*/ );
- err->collectTrace( EEPROM_COMP_NAME );
-
- break;
- }
-
- // EEPROM devices have write page boundaries, so when necessary
- // need to split up command into multiple write operations
-
- // Setup a max-size buffer of writePageSize
- size_t newBufLen = i_i2cInfo.writePageSize;
- newBuffer = static_cast<uint8_t*>(malloc( newBufLen ));
- needFree = true;
-
- // Point a uint8_t ptr at io_buffer for array addressing below
- uint8_t * l_data_ptr = reinterpret_cast<uint8_t*>(io_buffer);
-
- // Lock for operation sequencing
- mutex_lock( &g_eepromMutex );
- unlock = true;
-
- // variables to store different amount of data length
- size_t loop_data_length = 0;
- size_t total_bytes_written = 0;
-
- while( total_bytes_written < io_buflen )
- {
- // Determine how much data can be written in this loop
- // Can't go over a writePageSize boundary
-
- // Total data left to write
- data_left = io_buflen - total_bytes_written;
-
- // Difference to next writePageSize boundary
- diff_wps = i_i2cInfo.writePageSize -
- (i_i2cInfo.offset % i_i2cInfo.writePageSize);
-
- // Take the lesser of the 2 options
- loop_data_length = (data_left < diff_wps ) ? data_left : diff_wps;
-
- // Add the data the user wanted to write
- memcpy( newBuffer,
- &l_data_ptr[total_bytes_written],
- loop_data_length );
-
-
-
- // Check if loop_data_length crosses the EEPROM page boundary
- crossesEepromPageBoundary( i_i2cInfo.offset,
- loop_data_length,
- l_writeBuflen,
- l_bytesIntoSecondPage,
- i_i2cInfo );
-
- // Setup offset/address parms
- err = eepromPrepareAddress( i_target,
- &byteAddr,
- byteAddrSize,
- l_desiredPage,
- i_i2cInfo );
-
-
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- ERR_MRK"eepromWrite::eepromPrepareAddress()::loop version");
- break;
- }
-
-
-
- // if desired page has changed mid-request, switch to correct page
- if( l_desiredPage != l_originalPage )
- {
- l_switchPage = true;
- l_lockMutex = false;
- err = eepromPageOp( i_target,
- l_switchPage,
- l_lockMutex,
- l_pageLocked,
- l_desiredPage,
- i_i2cInfo );
- if( err )
- {
- TRACFCOMP( g_trac_eeprom,
- "Failed switching to new EEPROM page!");
- break;
- }
- l_originalPage = l_desiredPage;
- }
-
- TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop: %d/%d/0x%X "
- "writeBuflen=%d, offset=0x%X, bAS=%d, diffs=%d/%d",
- i_i2cInfo.port, i_i2cInfo.engine, i_i2cInfo.devAddr,
- l_writeBuflen, i_i2cInfo.offset, byteAddrSize,
- data_left, diff_wps);
-
- // Perform the requested write operation
- err = eepromWriteData( i_target,
- newBuffer,
- l_writeBuflen,
- &byteAddr,
- byteAddrSize,
- i_i2cInfo );
-
- if ( err )
- {
- // Can't assume that anything was written if
- // there was an error, so no update to total_bytes_written
- // for this loop
- TRACFCOMP(g_trac_eeprom,
- "Failed writing data: original eeprom write");
- break;
- }
-
- // Wait for EEPROM to write data to its internal memory
- // i_i2cInfo.writeCycleTime value in milliseconds
- nanosleep( 0, i_i2cInfo.writeCycleTime * NS_PER_MSEC );
-
- // Update how much data was written
- total_bytes_written += l_writeBuflen;
-
- // Update offset
- i_i2cInfo.offset += l_writeBuflen;
-
- TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop End: "
- "writeBuflen=%d, offset=0x%X, t_b_w=%d, io_buflen=%d",
- l_writeBuflen, i_i2cInfo.offset,
- total_bytes_written, io_buflen);
- } // end of write for-loop
-
- // Release mutex lock
- mutex_unlock( &g_eepromMutex );
- unlock = false;
-
-
- // Set how much data was actually written
- io_buflen = total_bytes_written;
-
-
- TRACSCOMP( g_trac_eepromr,
- "EEPROM WRITE END : Eeprom Role : %02d : Offset %.2X : Len %d",
- i_i2cInfo.eepromRole, i_i2cInfo.offset, io_buflen );
- } while( 0 );
-
- // Free memory
- if( needFree )
- {
- free( newBuffer );
- }
-
- // Catch it if we break out early.
- if( unlock )
- {
- mutex_unlock( & g_eepromMutex );
- }
-
-
- // Whether we failed in the main routine or not, unlock the page iff it is already
- // locked
- if( l_pageLocked )
- {
- errlHndl_t l_pageOpErrl = NULL;
-
- bool l_switchPage = false;
- bool l_lockMutex = false;
- l_pageOpErrl = eepromPageOp( i_target,
- l_switchPage,
- l_lockMutex,
- l_pageLocked,
- l_desiredPage,
- i_i2cInfo );
- if( l_pageOpErrl )
- {
- TRACFCOMP(g_trac_eeprom,
- "eepromWrite()::Failed unlocking page");
- errlCommit(l_pageOpErrl, I2C_COMP_ID);
- }
-
- }
TRACDCOMP( g_trac_eeprom,
- EXIT_MRK"eepromWrite()" );
-
- return err;
-
-} // end eepromWrite
-
-
-
-// ------------------------------------------------------------------
-// eepromWriteData
-// ------------------------------------------------------------------
-errlHndl_t eepromWriteData( TARGETING::Target * i_target,
- void * i_dataToWrite,
- size_t i_dataLen,
- void * i_byteAddress,
- size_t i_byteAddressSize,
- eeprom_addr_t i_i2cInfo )
-{
- TRACDCOMP( g_trac_eeprom,
- ENTER_MRK"eepromWriteData()");
- errlHndl_t err = NULL;
- errlHndl_t err_retryable = NULL;
- do
- {
- /***********************************************************/
- /* Attempt write multiple times ONLY on retryable fails */
- /***********************************************************/
- for (uint8_t retry = 0;
- retry <= EEPROM_MAX_RETRIES;
- retry++)
- {
- // Do the actual data write
- err = deviceOp( DeviceFW::WRITE,
- i_target,
- i_dataToWrite,
- i_dataLen,
- DEVICE_I2C_ADDRESS_OFFSET(
- i_i2cInfo.port,
- i_i2cInfo.engine,
- i_i2cInfo.devAddr,
- i_byteAddressSize,
- reinterpret_cast<uint8_t*>(
- i_byteAddress),
- i_i2cInfo.i2cMuxBusSelector,
- &(i_i2cInfo.i2cMuxPath) ) );
-
- if ( err == NULL )
- {
- // Operation completed successfully
- // break from retry loop
- break;
- }
- else if ( !errorIsRetryable( err->reasonCode() ) )
- {
- // Only retry on errorIsRetryable() failures: break from retry loop
- TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData(): I2C "
- "Write Non-Retryable fail %d/%d/0x%X, "
- "ldl=%d, offset=0x%X, aS=%d, retry=%d",
- i_i2cInfo.port, i_i2cInfo.engine,
- i_i2cInfo.devAddr, i_dataLen,
- i_i2cInfo.offset, i_i2cInfo.addrSize, retry);
-
- err->collectTrace(EEPROM_COMP_NAME);
-
- // break from retry loop
- break;
- }
- else // Handle retryable error
- {
- TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData(): I2C "
- "Write retryable fail %d/%d/0x%X, "
- "ldl=%d, offset=0x%X, aS=%d, writePageSize = %x",
- i_i2cInfo.port, i_i2cInfo.engine,
- i_i2cInfo.devAddr, i_dataLen,
- i_i2cInfo.offset, i_i2cInfo.addrSize,
- i_i2cInfo.writePageSize);
-
- // Printing mux info separately, if combined, nothing is displayed
- char* l_muxPath = i_i2cInfo.i2cMuxPath.toString();
- TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData():"
- "muxSelector=0x%X, muxPath=%s",
- i_i2cInfo.i2cMuxBusSelector,
- l_muxPath);
- free(l_muxPath);
- l_muxPath = nullptr;
-
- // If op will be attempted again: save error and continue
- if ( retry < EEPROM_MAX_RETRIES )
- {
- // Only save original retryable error
- if ( err_retryable == NULL )
- {
- // Save original retryable error
- err_retryable = err;
-
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): "
- "Error rc=0x%X, eid=0x%X plid=0x%X, "
- "tgt=0x%X, retry/MAX=%d/%d. Save error "
- "and retry",
- err_retryable->reasonCode(),
- err_retryable->eid(),
- err_retryable->plid(),
- TARGETING::get_huid(i_target),
- retry, EEPROM_MAX_RETRIES);
-
- err_retryable->collectTrace(EEPROM_COMP_NAME);
- }
- else
- {
- // Add data to original retryable error
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): "
- "Another Retryable Error rc=0x%X, eid=0x%X "
- "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. "
- "Delete error and retry",
- err->reasonCode(), err->eid(),
- err->plid(),
- TARGETING::get_huid(i_target),
- retry, EEPROM_MAX_RETRIES);
-
- ERRORLOG::ErrlUserDetailsString(
- "Another retryable ERROR found")
- .addToLog(err_retryable);
-
- // Delete this new retryable error
- delete err;
- err = NULL;
- }
-
- // continue to retry
- continue;
- }
- else // no more retries: trace and break
- {
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): "
- "Error rc=0x%X, tgt=0x%X. No More Retries "
- "(retry/MAX=%d/%d). Returning Error",
- err->reasonCode(),
- TARGETING::get_huid(i_target),
- retry, EEPROM_MAX_RETRIES);
-
- err->collectTrace(EEPROM_COMP_NAME);
-
- // break from retry loop
- break;
- }
- }
-
- } // end of retry loop
- /***********************************************************/
-
- // Handle saved retryable errors, if any
- if (err_retryable)
- {
- if (err)
- {
- // commit original retryable error with new err PLID
- err_retryable->plid(err->plid());
- TRACFCOMP(g_trac_eeprom, "eepromWriteData(): Committing saved "
- "retryable err eid=0x%X with plid of returned err: "
- "0x%X",
- err_retryable->eid(), err_retryable->plid());
-
- ERRORLOG::ErrlUserDetailsTarget(i_target)
- .addToLog(err_retryable);
-
- errlCommit(err_retryable, EEPROM_COMP_ID);
- }
- else
- {
- // Since we eventually succeeded, delete original retryable error
- TRACFCOMP(g_trac_eeprom, "eepromWriteData(): Op successful, "
- "deleting saved retryable err eid=0x%X, plid=0x%X",
- err_retryable->eid(), err_retryable->plid());
-
- delete err_retryable;
- err_retryable = NULL;
- }
- }
- }while( 0 );
- TRACDCOMP( g_trac_eeprom,
- EXIT_MRK"eepromWriteData()");
- return err;
-}
-
-
-
-// ------------------------------------------------------------------
-// eepromPrepareAddress
-// ------------------------------------------------------------------
-errlHndl_t eepromPrepareAddress ( TARGETING::Target * i_target,
- void * io_buffer,
- size_t & o_bufSize,
- uint8_t & o_desiredPage,
- eeprom_addr_t i_i2cInfo )
-{
- errlHndl_t err = NULL;
- o_bufSize = 0;
-
- TRACDCOMP( g_trac_eeprom,
- ENTER_MRK"eepromPrepareAddress()" );
-
- do
- {
-
- // --------------------------------------------------------------------
- // Currently only supporting I2C devices and that use 0, 1, or 2 bytes
- // to set the offset (ie, internal address) into the device.
- // --------------------------------------------------------------------
- switch( i_i2cInfo.addrSize )
- {
- case TWO_BYTE_ADDR:
- o_bufSize = 2;
- memset( io_buffer, 0x0, o_bufSize );
- *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFF00ull) >> 8;
- *((uint8_t*)io_buffer+1) = (i_i2cInfo.offset & 0x00FFull);
- break;
-
- case ONE_BYTE_ADDR_PAGESELECT:
- // If the offset is less than 256 bytes, report page zero, else page 1
- if( i_i2cInfo.offset >= EEPROM_PAGE_SIZE )
- {
- o_desiredPage = 1;
- }
- else
- {
- o_desiredPage = 0;
- }
- o_bufSize = 1;
- memset( io_buffer, 0x0, o_bufSize );
- *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFFull);
- break;
-
- case ONE_BYTE_ADDR:
- o_bufSize = 1;
- memset( io_buffer, 0x0, o_bufSize );
- *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFFull);
- break;
-
- case ZERO_BYTE_ADDR:
- o_bufSize = 0;
- // nothing to do with the buffer in this case
- break;
-
- default:
- TRACFCOMP( g_trac_eeprom,
- ERR_MRK"eepromPrepareAddress() - Invalid Device "
- "Address Size: 0x%08x", i_i2cInfo.addrSize);
-
- /*@
- * @errortype
- * @reasoncode EEPROM_INVALID_DEVICE_TYPE
- * @severity ERRL_SEV_UNRECOVERABLE
- * @moduleid EEPROM_PREPAREADDRESS
- * @userdata1 Address Size (aka Device Type)
- * @userdata2 EEPROM chip
- * @devdesc The Device type not supported (addrSize)
- * @custdesc A problem was detected during the IPL of
- * the system: Device type not supported.
- */
- err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_PREPAREADDRESS,
- EEPROM_INVALID_DEVICE_TYPE,
- i_i2cInfo.addrSize,
- i_i2cInfo.eepromRole,
- true /*Add HB SW Callout*/ );
-
- err->collectTrace( EEPROM_COMP_NAME );
-
- break;
- }
-
- } while( 0 );
-
- TRACDCOMP( g_trac_eeprom,
- EXIT_MRK"eepromPrepareAddress()" );
-
- return err;
-} // end eepromPrepareAddress
-
-
-// ------------------------------------------------------------------
-// eepromReadAttributes
-// ------------------------------------------------------------------
-errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
- eeprom_addr_t & o_i2cInfo )
-{
- errlHndl_t err = NULL;
- bool fail_reading_attribute = false;
-
- TRACDCOMP( g_trac_eeprom,
- ENTER_MRK"eepromReadAttributes() huid=0x%.8X",
- TARGETING::get_huid(i_target) );
-
- // These variables will be used to hold the EEPROM attribute data
- // Note: each 'EepromVpd' struct is kept the same via the attributes
- // so will be copying each to eepromData to save code space
- TARGETING::EepromVpdPrimaryInfo eepromData;
-
- do
- {
-
- switch (o_i2cInfo.eepromRole )
- {
- case VPD_PRIMARY:
- if( !( i_target->
- tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO>
- ( eepromData ) ) )
-
- {
- fail_reading_attribute = true;
- }
- break;
-
- case VPD_BACKUP:
-
- if( !(i_target->
- tryGetAttr<TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO>
- ( reinterpret_cast<
- TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO_type&>
- ( eepromData) ) ) )
- {
- fail_reading_attribute = true;
- }
- break;
-
- case SBE_PRIMARY:
- if( !(i_target->
- tryGetAttr<TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO>
- ( reinterpret_cast<
- TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO_type&>
- ( eepromData) ) ) )
- {
- fail_reading_attribute = true;
- }
- break;
-
- case SBE_BACKUP:
- if( (!i_target->
- tryGetAttr<TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO>
- ( reinterpret_cast<
- TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO_type&>
- ( eepromData) ) ) )
- {
- fail_reading_attribute = true;
- }
- break;
-
- default:
- TRACFCOMP( g_trac_eeprom,ERR_MRK"eepromReadAttributes() - "
- "Invalid chip (%d) to read attributes from!",
- o_i2cInfo.eepromRole );
-
- /*@
- * @errortype
- * @reasoncode EEPROM_INVALID_CHIP
- * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
- * @moduleid EEPROM_READATTRIBUTES
- * @userdata1 EEPROM Chip
- * @userdata2 HUID of target
- * @devdesc Invalid EEPROM chip to access
- */
- err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_READATTRIBUTES,
- EEPROM_INVALID_CHIP,
- o_i2cInfo.eepromRole,
- TARGETING::get_huid(i_target),
- true /*Add HB SW Callout*/ );
-
- err->collectTrace( EEPROM_COMP_NAME );
-
- break;
- }
-
- // Check if Attribute Data was found
- if( fail_reading_attribute == true )
- {
- TRACFCOMP( g_trac_eeprom,
- ERR_MRK"eepromReadAttributes() - ERROR reading "
- "attributes for eeprom role %d!",
- o_i2cInfo.eepromRole );
-
- /*@
- * @errortype
- * @reasoncode EEPROM_ATTR_INFO_NOT_FOUND
- * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
- * @moduleid EEPROM_READATTRIBUTES
- * @userdata1 HUID of target
- * @userdata2 EEPROM chip
- * @devdesc EEPROM attribute was not found
- */
- err = new ERRORLOG::ErrlEntry(
- ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_READATTRIBUTES,
- EEPROM_ATTR_INFO_NOT_FOUND,
- TARGETING::get_huid(i_target),
- o_i2cInfo.eepromRole);
-
- // Could be FSP or HB code's fault
- err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
- HWAS::SRCI_PRIORITY_MED);
- err->addProcedureCallout(HWAS::EPUB_PRC_SP_CODE,
- HWAS::SRCI_PRIORITY_MED);
-
- err->collectTrace( EEPROM_COMP_NAME );
-
- break;
-
- }
-
- // Successful reading of Attribute, so extract the data
- o_i2cInfo.port = eepromData.port;
- o_i2cInfo.devAddr = eepromData.devAddr;
- o_i2cInfo.engine = eepromData.engine;
- o_i2cInfo.i2cMasterPath = eepromData.i2cMasterPath;
- o_i2cInfo.writePageSize = eepromData.writePageSize;
- o_i2cInfo.devSize_KB = eepromData.maxMemorySizeKB;
- o_i2cInfo.chipCount = eepromData.chipCount;
- o_i2cInfo.writeCycleTime = eepromData.writeCycleTime;
- o_i2cInfo.i2cMuxBusSelector = eepromData.i2cMuxBusSelector;
- o_i2cInfo.i2cMuxPath = eepromData.i2cMuxPath;
-
- // Convert attribute info to eeprom_addr_size_t enum
- if ( eepromData.byteAddrOffset == 0x3 )
- {
- o_i2cInfo.addrSize = ONE_BYTE_ADDR;
- }
- else if ( eepromData.byteAddrOffset == 0x2 )
- {
- o_i2cInfo.addrSize = TWO_BYTE_ADDR;
- }
- else if ( eepromData.byteAddrOffset == 0x1 )
- {
- o_i2cInfo.addrSize = ONE_BYTE_ADDR_PAGESELECT;
- }
- else if ( eepromData.byteAddrOffset == 0x0 )
- {
- o_i2cInfo.addrSize = ZERO_BYTE_ADDR;
- }
- else
- {
- TRACFCOMP( g_trac_eeprom,
- ERR_MRK"eepromReadAttributes() - INVALID ADDRESS "
- "OFFSET SIZE %d!",
- o_i2cInfo.addrSize );
-
- /*@
- * @errortype
- * @reasoncode EEPROM_INVALID_ADDR_OFFSET_SIZE
- * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
- * @moduleid EEPROM_READATTRIBUTES
- * @userdata1 HUID of target
- * @userdata2 Address Offset Size
- * @devdesc Invalid address offset size
- */
- err = new ERRORLOG::ErrlEntry(
- ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_READATTRIBUTES,
- EEPROM_INVALID_ADDR_OFFSET_SIZE,
- TARGETING::get_huid(i_target),
- o_i2cInfo.addrSize,
- true /*Add HB SW Callout*/ );
-
- err->collectTrace( EEPROM_COMP_NAME );
-
- break;
-
- }
-
- } while( 0 );
-
- TRACUCOMP(g_trac_eeprom,"eepromReadAttributes() tgt=0x%X, %d/%d/0x%X "
- "wpw=0x%X, dsKb=0x%X, chpCnt=%d, aS=%d (%d)",
- TARGETING::get_huid(i_target),
- o_i2cInfo.port, o_i2cInfo.engine, o_i2cInfo.devAddr,
- o_i2cInfo.writePageSize, o_i2cInfo.devSize_KB,
- o_i2cInfo.chipCount, o_i2cInfo.addrSize,
- eepromData.byteAddrOffset);
-
-
-
- // Printing mux info separately, if combined, nothing is displayed
- char* l_muxPath = o_i2cInfo.i2cMuxPath.toString();
- TRACFCOMP(g_trac_eeprom, "eepromReadAttributes(): "
- "muxSelector=0x%X, muxPath=%s",
- o_i2cInfo.i2cMuxBusSelector,
- l_muxPath);
- free(l_muxPath);
- l_muxPath = nullptr;
-
- TRACDCOMP( g_trac_eeprom,
- EXIT_MRK"eepromReadAttributes()" );
-
- return err;
-} // end eepromReadAttributes
-
-
-// ------------------------------------------------------------------
-// eepromGetI2CMasterTarget
-// ------------------------------------------------------------------
-errlHndl_t eepromGetI2CMasterTarget ( TARGETING::Target * i_target,
- eeprom_addr_t i_i2cInfo,
- TARGETING::Target * &o_target )
-{
- errlHndl_t err = NULL;
- o_target = NULL;
-
- TRACDCOMP( g_trac_eeprom,
- ENTER_MRK"eepromGetI2CMasterTarget()" );
-
- do
- {
- TARGETING::TargetService& tS = TARGETING::targetService();
-
- // The path from i_target to its I2C Master was read from the
- // attribute via eepromReadAttributes() and passed to this function
- // in i_i2cInfo.i2cMasterPath
-
- // check that the path exists
- bool exists = false;
- tS.exists( i_i2cInfo.i2cMasterPath,
- exists );
-
- if( !exists )
- {
- TRACFCOMP( g_trac_eeprom,
- ERR_MRK"eepromGetI2CMasterTarget() - "
- "i2cMasterPath attribute path doesn't exist!" );
-
- // Compress the entity path
- uint64_t l_epCompressed = 0;
- for( uint32_t i = 0; i < i_i2cInfo.i2cMasterPath.size(); i++ )
- {
- // Path element: type:8 instance:8
- l_epCompressed |=
- i_i2cInfo.i2cMasterPath[i].type << (16*(3-i));
- l_epCompressed |=
- i_i2cInfo.i2cMasterPath[i].instance << ((16*(3-i))-8);
-
- // Can only fit 4 path elements into 64 bits
- if ( i == 3 )
- {
- break;
- }
- }
-
- /*@
- * @errortype
- * @reasoncode EEPROM_I2C_MASTER_PATH_ERROR
- * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
- * @moduleid EEPROM_GETI2CMASTERTARGET
- * @userdata1[00:31] Attribute Chip Type Enum
- * @userdata1[32:63] HUID of target
- * @userdata2 Compressed Entity Path
- * @devdesc I2C master entity path doesn't exist.
- */
- err = new ERRORLOG::ErrlEntry(
- ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_GETI2CMASTERTARGET,
- EEPROM_I2C_MASTER_PATH_ERROR,
- TWO_UINT32_TO_UINT64(
- i_i2cInfo.eepromRole,
- TARGETING::get_huid(i_target) ),
- l_epCompressed,
- true /*Add HB SW Callout*/ );
-
- err->collectTrace( EEPROM_COMP_NAME );
-
- char* l_masterPath = i_i2cInfo.i2cMasterPath.toString();
- ERRORLOG::ErrlUserDetailsString(l_masterPath).addToLog(err);
- free(l_masterPath);
- l_masterPath = nullptr;
-
- break;
- }
-
- // Since it exists, convert to a target
- o_target = tS.toTarget( i_i2cInfo.i2cMasterPath );
-
- if( NULL == o_target )
- {
- TRACFCOMP( g_trac_eeprom,
- ERR_MRK"eepromGetI2CMasterTarget() - I2C Master "
- "Path target was NULL!" );
-
- // Compress the entity path
- uint64_t l_epCompressed = 0;
- for( uint32_t i = 0; i < i_i2cInfo.i2cMasterPath.size(); i++ )
- {
- // Path element: type:8 instance:8
- l_epCompressed |=
- i_i2cInfo.i2cMasterPath[i].type << (16*(3-i));
- l_epCompressed |=
- i_i2cInfo.i2cMasterPath[i].instance << ((16*(3-i))-8);
-
- // Can only fit 4 path elements into 64 bits
- if ( i == 3 )
- {
- break;
- }
- }
-
- /*@
- * @errortype
- * @reasoncode EEPROM_TARGET_NULL
- * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
- * @moduleid EEPROM_GETI2CMASTERTARGET
- * @userdata1[00:31] Attribute Chip Type Enum
- * @userdata1[32:63] HUID of target
- * @userdata2 Compressed Entity Path
- * @devdesc I2C master path target is null.
- */
- err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_GETI2CMASTERTARGET,
- EEPROM_TARGET_NULL,
- TWO_UINT32_TO_UINT64(
- i_i2cInfo.eepromRole,
- TARGETING::get_huid(i_target) ),
- l_epCompressed,
- true /*Add HB SW Callout*/ );
-
- err->collectTrace( EEPROM_COMP_NAME );
-
- char* l_masterPath = i_i2cInfo.i2cMasterPath.toString();
- ERRORLOG::ErrlUserDetailsString(l_masterPath).addToLog(err);
- free(l_masterPath);
- l_masterPath = nullptr;
-
- break;
- }
-
- } while( 0 );
-
- TRACDCOMP( g_trac_eeprom,
- EXIT_MRK"eepromGetI2CMasterTarget()" );
+ EXIT_MRK"eepromPerformOp() - %s",
+ ((NULL == err) ? "No Error" : "With Error") );
return err;
-} // end eepromGetI2CMasterTarget
-
-
-/**
- * @brief Compare predicate for EepromInfo_t
- */
-class isSameEeprom
-{
- public:
- isSameEeprom( EepromInfo_t& i_first )
- : iv_first(i_first)
- {}
-
- bool operator()( EepromInfo_t& i_second )
- {
- return( (iv_first.i2cMaster == i_second.i2cMaster)
- && (iv_first.engine == i_second.engine)
- && (iv_first.port == i_second.port)
- && (iv_first.devAddr == i_second.devAddr) );
- }
- private:
- EepromInfo_t& iv_first;
-};
-
-/**
- * @brief Add any new EEPROMs associated with this target
- * to the list
- * @param[in] i_list : list of previously discovered EEPROMs
- * @param[out] i_targ : owner of EEPROMs to add
- */
-void add_to_list( std::list<EepromInfo_t>& i_list,
- TARGETING::Target* i_targ )
-{
- TRACFCOMP(g_trac_eeprom,"Targ %.8X",TARGETING::get_huid(i_targ));
-
- // try all defined types of EEPROMs
- for( eeprom_chip_types_t eep_type = FIRST_CHIP_TYPE;
- eep_type < LAST_CHIP_TYPE;
- eep_type = static_cast<eeprom_chip_types_t>(eep_type+1) )
- {
- bool found_eep = false;
- TARGETING::EepromVpdPrimaryInfo eepromData;
-
- switch( eep_type )
- {
- case VPD_PRIMARY:
- if( i_targ->
- tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO>
- ( eepromData ) )
-
- {
- found_eep = true;
- }
- break;
-
- case VPD_BACKUP:
- if( i_targ->
- tryGetAttr<TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO>
- ( reinterpret_cast<
- TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO_type&>
- ( eepromData) ) )
- {
- found_eep = true;
- }
- break;
-
- case SBE_PRIMARY:
- if( i_targ->
- tryGetAttr<TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO>
- ( reinterpret_cast<
- TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO_type&>
- ( eepromData) ) )
- {
- found_eep = true;
- }
- break;
-
- case SBE_BACKUP:
- if( i_targ->
- tryGetAttr<TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO>
- ( reinterpret_cast<
- TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO_type&>
- ( eepromData) ) )
- {
- found_eep = true;
- }
- break;
-
- case LAST_CHIP_TYPE:
- //only included to catch additional types later on
- found_eep = false;
- break;
- }
-
- if( !found_eep )
- {
- TRACDCOMP(g_trac_eeprom,"eep_type=%d not found",eep_type);
- //nothing to do
- continue;
- }
-
- // check that the path exists
- bool exists = false;
- TARGETING::targetService().exists( eepromData.i2cMasterPath,
- exists );
- if( !exists )
- {
- TRACDCOMP(g_trac_eeprom,"no master path");
- continue;
- }
-
- // Since it exists, convert to a target
- TARGETING::Target* i2cm = TARGETING::targetService()
- .toTarget( eepromData.i2cMasterPath );
- if( NULL == i2cm )
- {
- //not sure how this could happen, but just skip it
- TRACDCOMP(g_trac_eeprom,"no target");
- continue;
- }
-
- // ignore anything with junk data
- TARGETING::Target * sys = NULL;
- TARGETING::targetService().getTopLevelTarget( sys );
- if( i2cm == sys )
- {
- TRACDCOMP(g_trac_eeprom,"sys target");
- continue;
- }
-
- // copy all the data out
- EepromInfo_t eep_info;
- eep_info.i2cMaster = i2cm;
- eep_info.engine = eepromData.engine;
- eep_info.port = eepromData.port;
- eep_info.devAddr = eepromData.devAddr;
- eep_info.device = eep_type;
- eep_info.assocTarg = i_targ;
- eep_info.chipCount = eepromData.chipCount;
- eep_info.sizeKB = eepromData.maxMemorySizeKB;
- eep_info.addrBytes = eepromData.byteAddrOffset;
- //one more lookup for the speed
- TARGETING::ATTR_I2C_BUS_SPEED_ARRAY_type speeds;
- if( i2cm->tryGetAttr<TARGETING::ATTR_I2C_BUS_SPEED_ARRAY>
- (speeds) )
- {
- if( (eep_info.engine > I2C_BUS_MAX_ENGINE(speeds))
- || (eep_info.port > I2C_BUS_MAX_PORT(speeds)) )
- {
- TRACDCOMP(g_trac_eeprom,"bad engine/port");
- continue;
- }
- eep_info.busFreq = speeds[eep_info.engine][eep_info.port];
- eep_info.busFreq *= 1000; //convert KHz->Hz
- }
- else
- {
- TRACDCOMP(g_trac_eeprom,"eep_type=%d, Speed=0",eep_type);
- continue;
- }
-
- // check if the eeprom is already in our list
- std::list<EepromInfo_t>::iterator oldeep =
- find_if( i_list.begin(), i_list.end(),
- isSameEeprom(eep_info) );
- if( oldeep == i_list.end() )
- {
- // didn't find it in our list so stick it into the output list
- i_list.push_back(eep_info);
- TRACFCOMP(g_trac_eeprom,"--Adding i2cm=%.8X, type=%d, eng=%d, port=%d, addr=%.2X for %.8X", TARGETING::get_huid(i2cm),eep_type,eepromData.engine,eepromData.port, eep_info.devAddr, TARGETING::get_huid(eep_info.assocTarg));
- }
- else
- {
- TRACFCOMP(g_trac_eeprom,"--Skipping duplicate i2cm=%.8X, type=%d, eng=%d, port=%d, addr=%.2X for %.8X", TARGETING::get_huid(i2cm),eep_type,eepromData.engine,eepromData.port, eep_info.devAddr, TARGETING::get_huid(eep_info.assocTarg));
- }
- }
-}
-
-/**
- * @brief Return a set of information related to every unique
- * EEPROM in the system
- */
-void getEEPROMs( std::list<EepromInfo_t>& o_info )
-{
- TRACFCOMP(g_trac_eeprom,">>getEEPROMs()");
-
- // We only want to have a single entry in our list per
- // physical EEPROM. Since multiple targets could be
- // using the same EEPROM, we need to have a hierarchy
- // of importance.
- // node/planar > proc > membuf > dimm
-
- // predicate to only look for this that are actually there
- TARGETING::PredicateHwas isPresent;
- isPresent.reset().poweredOn(true).present(true);
+} // end eepromPerformOp
- // #1 - Nodes
- TARGETING::PredicateCTM nodes( TARGETING::CLASS_ENC,
- TARGETING::TYPE_NODE,
- TARGETING::MODEL_NA );
- TARGETING::PredicatePostfixExpr l_nodeFilter;
- l_nodeFilter.push(&isPresent).push(&nodes).And();
- TARGETING::TargetRangeFilter node_itr( TARGETING::targetService().begin(),
- TARGETING::targetService().end(),
- &l_nodeFilter );
- for( ; node_itr; ++node_itr )
- {
- add_to_list( o_info, *node_itr );
- }
+// Register the perform Op with the routing code for Procs.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::EEPROM,
+ TARGETING::TYPE_PROC,
+ eepromPerformOp );
- // #2 - Procs
- TARGETING::PredicateCTM procs( TARGETING::CLASS_CHIP,
- TARGETING::TYPE_PROC,
- TARGETING::MODEL_NA );
- TARGETING::PredicatePostfixExpr l_procFilter;
- l_procFilter.push(&isPresent).push(&procs).And();
- TARGETING::TargetRangeFilter proc_itr( TARGETING::targetService().begin(),
- TARGETING::targetService().end(),
- &l_procFilter );
- for( ; proc_itr; ++proc_itr )
- {
- add_to_list( o_info, *proc_itr );
- }
+// Register the perform Op with the routing code for DIMMs.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::EEPROM,
+ TARGETING::TYPE_DIMM,
+ eepromPerformOp );
- // #3 - Membufs
- TARGETING::PredicateCTM membs( TARGETING::CLASS_CHIP,
- TARGETING::TYPE_MEMBUF,
- TARGETING::MODEL_NA );
- TARGETING::PredicatePostfixExpr l_membFilter;
- l_membFilter.push(&isPresent).push(&membs).And();
- TARGETING::TargetRangeFilter memb_itr( TARGETING::targetService().begin(),
- TARGETING::targetService().end(),
- &l_membFilter );
- for( ; memb_itr; ++memb_itr )
- {
- add_to_list( o_info, *memb_itr );
- }
+// Register the perform Op with the routing code for Memory Buffers.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::EEPROM,
+ TARGETING::TYPE_MEMBUF,
+ eepromPerformOp );
- // #4 - DIMMs
- TARGETING::PredicateCTM dimms( TARGETING::CLASS_LOGICAL_CARD,
- TARGETING::TYPE_DIMM,
- TARGETING::MODEL_NA );
- TARGETING::PredicatePostfixExpr l_dimmFilter;
- l_dimmFilter.push(&isPresent).push(&dimms).And();
- TARGETING::TargetRangeFilter dimm_itr( TARGETING::targetService().begin(),
- TARGETING::targetService().end(),
- &l_dimmFilter );
- for( ; dimm_itr; ++dimm_itr )
- {
- #ifdef CONFIG_NVDIMM
- // Skip if this is an NVDIMM as this will get added later
- if (TARGETING::isNVDIMM( *dimm_itr ))
- continue;
- #endif
- add_to_list( o_info, *dimm_itr );
- }
+// Register the perform Op with the routing code for Nodes.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::EEPROM,
+ TARGETING::TYPE_NODE,
+ eepromPerformOp );
- TRACFCOMP(g_trac_eeprom,"<<getEEPROMs()");
-}
+// Register the perform Op with the routing code for MCS chiplets.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::EEPROM,
+ TARGETING::TYPE_MCS,
+ eepromPerformOp );
+// Register the perform Op with the routing code for Open-Capi Memory Buffer Chips.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::EEPROM,
+ TARGETING::TYPE_OCMB_CHIP,
+ eepromPerformOp );
} // end namespace EEPROM
diff --git a/src/usr/i2c/eepromdd_hardware.C b/src/usr/i2c/eepromdd_hardware.C
new file mode 100644
index 000000000..351ca549a
--- /dev/null
+++ b/src/usr/i2c/eepromdd_hardware.C
@@ -0,0 +1,1364 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/i2c/eepromdd_hardware.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2019 */
+/* [+] 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 */
+#include "eepromdd_hardware.H"
+#include <sys/time.h>
+#include "errlud_i2c.H"
+#include <i2c/eepromif.H>
+#include <i2c/i2cif.H>
+#include <errl/errlmanager.H>
+#include <i2c/i2creasoncodes.H>
+#include <i2c/eepromddreasoncodes.H>
+#include <errl/errludstring.H>
+#include <errl/errludtarget.H>
+
+extern trace_desc_t* g_trac_eeprom;
+
+// ----------------------------------------------
+// Globals
+// ----------------------------------------------
+mutex_t g_eepromMutex = MUTEX_INITIALIZER;
+
+// Easy macro replace for unit testing
+//#define TRACUCOMP(args...) TRACFCOMP(args)
+#define TRACUCOMP(args...)
+
+namespace
+{
+
+// ------------------------------------------------------------------
+// errorIsRetryable
+// ------------------------------------------------------------------
+static bool errorIsRetryable(uint16_t reasonCode)
+{
+ return reasonCode == I2C::I2C_NACK_ONLY_FOUND ||
+ reasonCode == I2C::I2C_ARBITRATION_LOST_ONLY_FOUND;
+}
+
+}
+
+namespace EEPROM
+{
+
+errlHndl_t eepromPerformOpHW(DeviceFW::OperationType i_opType,
+ TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t & io_buflen,
+ eeprom_addr_t & io_i2cInfo)
+{
+#ifdef __HOSTBOOT_RUNTIME
+ // At runtime the OCC sensor cache will need to be disabled to avoid I2C
+ // collisions. This bool indicates the sensor cache was enabled but is
+ // now disabled and needs to be re-enabled when the eeprom op completes.
+ bool scacDisabled = false;
+#endif //__HOSTBOOT_RUNTIME
+ TARGETING::Target * i2cMasterTarget = nullptr;
+ void * l_pBuffer = io_buffer;
+ size_t l_currentOpLen = io_buflen;
+ size_t l_remainingOpLen = io_buflen;
+ errlHndl_t err = nullptr;
+
+ do
+ {
+ // Read Attributes needed to complete the operation
+ err = eepromReadAttributes( i_target,
+ io_i2cInfo );
+
+ if( err )
+ {
+ break;
+ }
+
+ size_t l_snglChipSize = (io_i2cInfo.devSize_KB * KILOBYTE)
+ / io_i2cInfo.chipCount;
+
+ // Check to see if we need to find a new target for
+ // the I2C Master
+ err = eepromGetI2CMasterTarget( i_target,
+ io_i2cInfo,
+ i2cMasterTarget );
+
+ if( err )
+ {
+ break;
+ }
+
+ // Check that the offset + data length is less than device max size
+ if ( ( io_i2cInfo.offset + io_buflen ) >
+ ( io_i2cInfo.devSize_KB * KILOBYTE ) )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromPerformOp(): Device Overflow! "
+ "C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X "
+ "devSizeKB=0x%X", io_i2cInfo.eepromRole, io_i2cInfo.engine,
+ io_i2cInfo.port, io_i2cInfo.devAddr, io_i2cInfo.offset,
+ io_buflen, io_i2cInfo.devSize_KB);
+
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_OVERFLOW_ERROR
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_PERFORM_OP
+ * @userdata1[0:31] Offset
+ * @userdata1[32:63] Buffer Length
+ * @userdata2 Device Max Size (in KB)
+ * @devdesc I2C Buffer Length + Offset > Max Size
+ * @custdesc A problem occurred during the IPL of the
+ * system: I2C buffer offset is too large.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_PERFORM_OP,
+ EEPROM_OVERFLOW_ERROR,
+ TWO_UINT32_TO_UINT64(
+ io_i2cInfo.offset,
+ io_buflen ),
+ io_i2cInfo.devSize_KB,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( EEPROM_COMP_NAME );
+
+ break;
+ }
+
+ // Adjust offset and devAddr to the correct starting chip
+ while( io_i2cInfo.offset >= l_snglChipSize )
+ {
+ io_i2cInfo.offset -= l_snglChipSize;
+ io_i2cInfo.devAddr += EEPROM_DEVADDR_INC;
+ }
+
+ // Keep first op length within a chip
+ if( ( io_i2cInfo.offset + io_buflen ) > l_snglChipSize )
+ {
+ l_currentOpLen = l_snglChipSize - io_i2cInfo.offset;
+ }
+
+ TRACFCOMP( g_trac_eeprom,
+ "eepromPerformOp(): i_opType=%d "
+ "C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X, ",
+ i_opType, io_i2cInfo.eepromRole, io_i2cInfo.engine,
+ io_i2cInfo.port, io_i2cInfo.devAddr, io_i2cInfo.offset, io_buflen)
+
+ TRACFCOMP (g_trac_eeprom,
+ "eepromPerformOp(): snglChipKB=0x%X, chipCount=0x%X, devSizeKB=0x%X",
+ l_snglChipSize, io_i2cInfo.chipCount, io_i2cInfo.devSize_KB);
+
+ // Printing mux info separately, if combined, nothing is displayed
+ char* l_muxPath = io_i2cInfo.i2cMuxPath.toString();
+ TRACFCOMP(g_trac_eeprom, "eepromPerformOp(): "
+ "muxSelector=0x%X, muxPath=%s",
+ io_i2cInfo.i2cMuxBusSelector,
+ l_muxPath);
+ free(l_muxPath);
+ l_muxPath = nullptr;
+
+#ifdef __HOSTBOOT_RUNTIME
+ // Disable Sensor Cache if the I2C master target is MEMBUF
+ if( i2cMasterTarget->getAttr<TARGETING::ATTR_TYPE>() ==
+ TARGETING::TYPE_MEMBUF )
+ {
+ err = I2C::i2cDisableSensorCache(i2cMasterTarget,scacDisabled);
+ if ( err )
+ {
+ break;
+ }
+ }
+#endif //__HOSTBOOT_RUNTIME
+
+ // Do the read or write
+ while(l_remainingOpLen > 0)
+ {
+ if( i_opType == DeviceFW::READ )
+ {
+ err = eepromRead( i2cMasterTarget,
+ l_pBuffer,
+ l_currentOpLen,
+ io_i2cInfo );
+ }
+ else if( i_opType == DeviceFW::WRITE )
+ {
+ err = eepromWrite( i2cMasterTarget,
+ l_pBuffer,
+ l_currentOpLen,
+ io_i2cInfo );
+ }
+ else
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromPerformOp(): "
+ "Invalid EEPROM Operation!");
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_INVALID_OPERATION
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_PERFORM_OP
+ * @userdata1 Operation Type
+ * @userdata2 Chip to Access
+ * @devdesc Invalid operation type.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_PERFORM_OP,
+ EEPROM_INVALID_OPERATION,
+ i_opType,
+ io_i2cInfo.eepromRole,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( EEPROM_COMP_NAME );
+ }
+
+ if ( err )
+ {
+ break;
+ }
+
+ // Adjust the buffer pointer and remaining op length
+ l_pBuffer = (void *)(reinterpret_cast<uint64_t>(l_pBuffer)
+ + l_currentOpLen);
+ l_remainingOpLen -= l_currentOpLen;
+
+ if( l_remainingOpLen > l_snglChipSize )
+ {
+ // Keep next op length within a chip
+ l_currentOpLen = l_snglChipSize;
+ }
+ else if( l_remainingOpLen > 0 )
+ {
+ // Set next op length to what is left to do
+ l_currentOpLen = l_remainingOpLen;
+ }
+ else
+ {
+ // Break if there is nothing left to do
+ break;
+ }
+
+ // Prepare the address at the start of next EEPROM
+ io_i2cInfo.offset = 0;
+ io_i2cInfo.devAddr += EEPROM_DEVADDR_INC;
+ } // Do the read or write
+ } while( 0 );
+
+#ifdef __HOSTBOOT_RUNTIME
+ // Re-enable sensor cache if it was disabled before the eeprom op and
+ // the I2C master target is MEMBUF
+ if( scacDisabled &&
+ (i2cMasterTarget->getAttr<TARGETING::ATTR_TYPE>() == TARGETING::TYPE_MEMBUF) )
+ {
+ errlHndl_t tmp_err = NULL;
+
+ tmp_err = I2C::i2cEnableSensorCache(i2cMasterTarget);
+
+ if( err && tmp_err)
+ {
+ delete tmp_err;
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK" Enable Sensor Cache failed for HUID=0x%.8X",
+ TARGETING::get_huid(i2cMasterTarget));
+ }
+ else if(tmp_err)
+ {
+ err = tmp_err;
+ }
+ }
+#endif //__HOSTBOOT_RUNTIME
+
+ // If there is an error, add parameter info to log
+ if ( err != NULL )
+ {
+ EEPROM::UdEepromParms( i_opType,
+ i_target,
+ io_buflen,
+ io_i2cInfo )
+ .addToLog(err);
+ }
+
+ return err;
+}
+
+// ------------------------------------------------------------------
+// eepromPageOp
+// ------------------------------------------------------------------
+errlHndl_t eepromPageOp( TARGETING::Target * i_target,
+ bool i_switchPage,
+ bool i_lockMutex,
+ bool & io_pageLocked,
+ uint8_t i_desiredPage,
+ const eeprom_addr_t & i_i2cInfo )
+{
+ TRACUCOMP(g_trac_eeprom,
+ ENTER_MRK"eepromPageOp()");
+
+ errlHndl_t l_err = NULL;
+ size_t l_placeHolderZero = 0;
+
+ do
+ {
+ // DDR4 requires EEPROM page to be selected before read/write operation.
+ // The following operation locks the EEPROM_PAGE attribute behind a
+ // mutex and switches all DIMMs on the I2C bus to the appropriate
+ // page.
+ if( i_i2cInfo.addrSize == ONE_BYTE_ADDR_PAGESELECT )
+ {
+
+ bool l_lockPage;
+ if( i_switchPage )
+ {
+ // we want to switch to the desired page
+ l_lockPage = true;
+ l_err = deviceOp( DeviceFW::WRITE,
+ i_target,
+ NULL,
+ l_placeHolderZero,
+ DEVICE_I2C_CONTROL_PAGE_OP(
+ i_i2cInfo.port,
+ i_i2cInfo.engine,
+ l_lockPage,
+ i_desiredPage,
+ i_lockMutex ));
+
+ if( l_err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "eepromPageOp::Failed locking EEPROM page");
+ break;
+ }
+ // if we make it this far, we successfully locked the page mutex
+ io_pageLocked = true;
+ }
+ else
+ {
+ // we only want to unlock the page
+ l_lockPage = false;
+ l_err = deviceOp( DeviceFW::WRITE,
+ i_target,
+ NULL,
+ l_placeHolderZero,
+ DEVICE_I2C_CONTROL_PAGE_OP(
+ i_i2cInfo.port,
+ i_i2cInfo.engine,
+ l_lockPage,
+ l_placeHolderZero,
+ i_lockMutex ));
+
+ if( l_err )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "eepromPageOp()::failed unlocking EEPROM page");
+ break;
+ }
+ // if we make it this far, we successfully unlocked the page
+ io_pageLocked = false;
+ }
+ }
+ }while(0);
+ TRACUCOMP(g_trac_eeprom,
+ EXIT_MRK"eepromPageOp()");
+ return l_err;
+}
+
+
+// ------------------------------------------------------------------
+// crossesEepromPageBoundary
+// ------------------------------------------------------------------
+bool crossesEepromPageBoundary( uint64_t i_originalOffset,
+ size_t i_originalLen,
+ size_t & io_newLen,
+ size_t & o_pageTwoBuflen,
+ const eeprom_addr_t& i_i2cInfo )
+{
+ bool l_boundaryCrossed = false;
+ size_t l_higherBound = i_originalOffset + i_originalLen;
+
+ if( ( i_i2cInfo.addrSize == ONE_BYTE_ADDR_PAGESELECT ) &&
+ ( ( i_originalOffset < EEPROM_PAGE_SIZE ) &&
+ ( l_higherBound > EEPROM_PAGE_SIZE) ) )
+ {
+ // The read/write request crosses the boundary
+ l_boundaryCrossed = true;
+
+ // Calculate the new length of the page 0 buffer and the
+ // length of the page 1 buffer
+ o_pageTwoBuflen = l_higherBound - EEPROM_PAGE_SIZE;
+ io_newLen = i_originalLen - o_pageTwoBuflen;
+ }
+ else
+ {
+ // The read/write request does not cross the boundary.
+ // Update new length to be used by subsequent operations
+ io_newLen = i_originalLen;
+ o_pageTwoBuflen = 0;
+ }
+
+ return l_boundaryCrossed;
+}
+
+
+
+// ------------------------------------------------------------------
+// eepromRead
+// ------------------------------------------------------------------
+errlHndl_t eepromRead ( TARGETING::Target * i_target,
+ void * o_buffer,
+ size_t i_buflen,
+ eeprom_addr_t i_i2cInfo )
+{
+ errlHndl_t err = NULL;
+ uint8_t byteAddr[MAX_BYTE_ADDR];
+ size_t byteAddrSize = 0;
+ bool l_pageLocked = false;
+ uint8_t l_desiredPage = 0;
+ bool l_boundaryCrossed = false;
+ size_t l_readBuflen = 0;
+ size_t l_pageTwoBuflen = 0;
+
+ TRACUCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromRead()" );
+
+ do
+ {
+ TRACUCOMP( g_trac_eeprom,
+ "EEPROM READ START : Chip: %02d : Offset %.2X : Len %d",
+ i_i2cInfo.chip, i_i2cInfo.offset, i_buflen );
+
+ // At maximum we want to do 1 KB reads at a time. The largest that
+ // the scom byte range will support is 64 KB - 1 but we will do 1
+ // KB at a time to catch fails faster. This is useful when we do big
+ // reads when caching the eeprom to pnor.
+ size_t l_readLenRemaining = i_buflen;
+ size_t l_currentReadLen;
+
+ // Lock to sequence operations
+ mutex_lock( &g_eepromMutex );
+
+ while( l_readLenRemaining > 0 )
+ {
+ l_currentReadLen = l_readLenRemaining < KILOBYTE ? l_readLenRemaining : KILOBYTE;
+
+ // Check to see if the Read operation straddles the EEPROM page
+ // boundary.Note this is only required for systems w/ DDR4 industry
+ // standard dimms. DDR4 ISDIMMS have a max of 512 bytes so we will
+ // never loop through this multiple times on those systems
+ l_boundaryCrossed = crossesEepromPageBoundary( i_i2cInfo.offset,
+ l_currentReadLen,
+ l_readBuflen,
+ l_pageTwoBuflen,
+ i_i2cInfo );
+
+ // Set addressing parameters
+ err = eepromPrepareAddress( i_target,
+ &byteAddr,
+ byteAddrSize,
+ l_desiredPage,
+ i_i2cInfo);
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"eepromRead()::eepromPrepareAddress()");
+ break;
+ }
+
+
+ // Attempt to lock page mutex
+ // (only important in DDR4 IS-DIMM systems)
+ bool l_switchPage = true;
+ bool l_lockMutex = true;
+ err = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "eepromRead()::eepromPageOp()::failed locking page");
+ break;
+ }
+
+ // First Read. If Second read is necessary, this call will read
+ // everything from the original offset up to the 256th byte
+ err = eepromReadData( i_target,
+ &(reinterpret_cast<uint8_t*>(o_buffer)[i_buflen - l_readLenRemaining]),
+ l_readBuflen,
+ &byteAddr,
+ byteAddrSize,
+ i_i2cInfo );
+
+ i_i2cInfo.offset += l_currentReadLen;
+ l_readLenRemaining -= l_currentReadLen;
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "Failed reading data: original read");
+ break;
+ }
+
+
+ // Perform the second Read if necessary. Read starts at
+ // begining of EEPROM page 1 (offset=0x100) and reads the
+ // rest of the required data.
+ if( l_boundaryCrossed )
+ {
+ //Prepare the address to read at the start of EEPROM page one
+ i_i2cInfo.offset = EEPROM_PAGE_SIZE; // 0x100
+ err = eepromPrepareAddress( i_target,
+ &byteAddr,
+ byteAddrSize,
+ l_desiredPage,
+ i_i2cInfo );
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "Error preparing address: second eeprom read");
+ break;
+ }
+
+ // Switch to the second EEPROM page
+ l_switchPage = true;
+ l_lockMutex = false;
+ err = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "Failed switching to EEPROM page 1 for second read op");
+ break;
+ }
+
+ // Perform the second read operation
+ err = eepromReadData(
+ i_target,
+ &(reinterpret_cast<uint8_t*>(o_buffer)[l_readBuflen]),
+ l_pageTwoBuflen,
+ &byteAddr,
+ byteAddrSize,
+ i_i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "Failed reading data: second read");
+ break;
+ }
+ }
+ }
+
+
+ TRACUCOMP( g_trac_eeprom,
+ "EEPROM READ END : Eeprom Role: %02d : Offset %.2X : Len %d : %016llx",
+ i_i2cInfo.eepromRole, i_i2cInfo.offset, i_buflen,
+ *((uint64_t*)o_buffer) );
+
+ } while( 0 );
+
+ // Unlock eeprom mutex no matter what
+ mutex_unlock( & g_eepromMutex );
+
+ // Whether we failed in the main routine or not, unlock page iff the page is locked
+ if( l_pageLocked )
+ {
+ errlHndl_t l_pageOpErrl = NULL;
+ bool l_switchPage = false;
+ bool l_lockMutex = false;
+ l_pageOpErrl = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+ if( l_pageOpErrl )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "eepromRead()::Failed unlocking page");
+ errlCommit(l_pageOpErrl, I2C_COMP_ID);
+ }
+
+ }
+
+ TRACUCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromRead()" );
+
+ return err;
+} // end eepromRead
+
+
+// ------------------------------------------------------------------
+// eepromReadData
+// ------------------------------------------------------------------
+errlHndl_t eepromReadData( TARGETING::Target * i_target,
+ void * o_buffer,
+ size_t i_buflen,
+ void * i_byteAddress,
+ size_t i_byteAddressSize,
+ eeprom_addr_t i_i2cInfo )
+{
+ errlHndl_t l_err = NULL;
+ errlHndl_t err_retryable = NULL;
+
+ TRACUCOMP(g_trac_eeprom,
+ ENTER_MRK"eepromReadData()");
+ do
+ {
+ /************************************************************/
+ /* Attempt read multiple times ONLY on retryable fails */
+ /************************************************************/
+ for (uint8_t retry = 0;
+ retry <= EEPROM_MAX_RETRIES;
+ retry++)
+ {
+
+ // Only write the byte address if we have data to write
+ if( 0 != i_byteAddressSize )
+ {
+ // Use the I2C MUX OFFSET Interface for the READ
+ l_err = deviceOp( DeviceFW::READ,
+ i_target,
+ o_buffer,
+ i_buflen,
+ DEVICE_I2C_ADDRESS_OFFSET(
+ i_i2cInfo.port,
+ i_i2cInfo.engine,
+ i_i2cInfo.devAddr,
+ i_byteAddressSize,
+ reinterpret_cast<uint8_t*>(i_byteAddress),
+ i_i2cInfo.i2cMuxBusSelector,
+ &(i_i2cInfo.i2cMuxPath)));
+
+ if( l_err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"eepromReadData(): I2C Read-Offset failed on "
+ "%d/%d/0x%X aS=%d",
+ i_i2cInfo.port, i_i2cInfo.engine,
+ i_i2cInfo.devAddr, i_byteAddressSize);
+ TRACFBIN(g_trac_eeprom, "i_byteAddress[]",
+ i_byteAddress, i_byteAddressSize);
+
+ // Don't break here -- error handled below
+ }
+ }
+ else
+ {
+ // Do the actual read via I2C
+ l_err = deviceOp( DeviceFW::READ,
+ i_target,
+ o_buffer,
+ i_buflen,
+ DEVICE_I2C_ADDRESS(
+ i_i2cInfo.port,
+ i_i2cInfo.engine,
+ i_i2cInfo.devAddr,
+ i_i2cInfo.i2cMuxBusSelector,
+ &(i_i2cInfo.i2cMuxPath) ) );
+
+ if( l_err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"eepromReadData(): I2C Read failed on "
+ "%d/%d/0x%0X", i_i2cInfo.port, i_i2cInfo.engine,
+ i_i2cInfo.devAddr);
+
+ // Don't break here -- error handled below
+ }
+ }
+
+ if ( l_err == NULL )
+ {
+ // Operation completed successfully
+ // break from retry loop
+ break;
+ }
+ else if ( !errorIsRetryable( l_err->reasonCode() ) )
+ {
+ // Only retry on errorIsRetryable() failures: break from retry loop
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): 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(EEPROM_COMP_NAME);
+
+ // break from retry loop
+ break;
+ }
+ else // Handle retryable error
+ {
+ // If op will be attempted again: save log and continue
+ if ( retry < EEPROM_MAX_RETRIES )
+ {
+ // Only save original retryable error
+ if ( err_retryable == NULL )
+ {
+ // Save original retryable error
+ err_retryable = l_err;
+
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): "
+ "Retryable Error rc=0x%X, eid=0x%X, tgt=0x%X, "
+ "retry/MAX=%d/%d. Save error and retry",
+ err_retryable->reasonCode(),
+ err_retryable->eid(),
+ TARGETING::get_huid(i_target),
+ retry, EEPROM_MAX_RETRIES);
+
+ err_retryable->collectTrace(EEPROM_COMP_NAME);
+ }
+ else
+ {
+ // Add data to original retryable error
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): "
+ "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, EEPROM_MAX_RETRIES);
+
+ ERRORLOG::ErrlUserDetailsString(
+ "Another Retryable ERROR found")
+ .addToLog(err_retryable);
+
+ // Delete this new retryable error
+ delete l_err;
+ l_err = NULL;
+ }
+
+ // continue to retry
+ continue;
+ }
+ else // no more retries: trace and break
+ {
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): "
+ "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, EEPROM_MAX_RETRIES);
+
+ l_err->collectTrace(EEPROM_COMP_NAME);
+
+ // break from retry loop
+ break;
+ }
+ }
+
+ } // end of retry loop
+
+ // Handle saved retryable error, if any
+ if (err_retryable)
+ {
+ if (l_err)
+ {
+ // commit original retryable error with new err PLID
+ err_retryable->plid(l_err->plid());
+ TRACFCOMP(g_trac_eeprom, "eepromReadData(): Committing saved retryable "
+ "l_err eid=0x%X with plid of returned err: 0x%X",
+ err_retryable->eid(), err_retryable->plid());
+
+ ERRORLOG::ErrlUserDetailsTarget(i_target)
+ .addToLog(err_retryable);
+
+ errlCommit(err_retryable, EEPROM_COMP_ID);
+ }
+ else
+ {
+ // Since we eventually succeeded, delete original retryable error
+ TRACFCOMP(g_trac_eeprom, "eepromReadData(): Op successful, "
+ "deleting saved retryable err eid=0x%X, plid=0x%X",
+ err_retryable->eid(), err_retryable->plid());
+
+ delete err_retryable;
+ err_retryable = NULL;
+ }
+ }
+
+ }while( 0 );
+
+ TRACUCOMP(g_trac_eeprom,
+ EXIT_MRK"eepromReadData");
+ return l_err;
+}
+
+
+
+// ------------------------------------------------------------------
+// eepromWrite
+// ------------------------------------------------------------------
+errlHndl_t eepromWrite ( TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t & io_buflen,
+ eeprom_addr_t i_i2cInfo )
+{
+ errlHndl_t err = NULL;
+ uint8_t l_desiredPage = 0;
+ uint8_t l_originalPage = 0;
+ uint8_t byteAddr[MAX_BYTE_ADDR];
+ size_t byteAddrSize = 0;
+ uint8_t * newBuffer = NULL;
+ bool needFree = false;
+ bool unlock = false;
+ bool l_pageLocked = false;
+ uint32_t data_left = 0;
+ uint32_t diff_wps = 0;
+ size_t l_writeBuflen = 0;
+ size_t l_bytesIntoSecondPage = 0;
+
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromWrite()" );
+
+ do
+ {
+ TRACUCOMP( g_trac_eeprom,
+ "EEPROM WRITE START : Eeprom Role : %02d : Offset %.2X : Len %d : %016llx",
+ i_i2cInfo.eepromRole, i_i2cInfo.offset, io_buflen,
+ *((uint64_t*)io_buffer) );
+
+
+ // Prepare address parameters
+ err = eepromPrepareAddress( i_target,
+ &byteAddr,
+ byteAddrSize,
+ l_desiredPage,
+ i_i2cInfo);
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"eepromWrite()::eepromPrepareAddress()");
+ break;
+ }
+
+ // Save original Page
+ l_originalPage = l_desiredPage;
+ // Attempt to lock page mutex
+ bool l_switchPage = true; // true: Lock and switch page
+ // false: Just unlock page
+ bool l_lockMutex = true; // true: Lock mutex
+ // false: Skip locking mutex step
+ err = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "eepromWrite()::Failed locking EEPROM page");
+ break;
+ }
+
+ // Check for writePageSize of zero
+ if ( i_i2cInfo.writePageSize == 0 )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromWrite(): writePageSize is 0!");
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_I2C_WRITE_PAGE_SIZE_ZERO
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_WRITE
+ * @userdata1 HUID of target
+ * @userdata2 Chip to Access
+ * @devdesc I2C write page size is zero.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_WRITE,
+ EEPROM_I2C_WRITE_PAGE_SIZE_ZERO,
+ TARGETING::get_huid(i_target),
+ i_i2cInfo.eepromRole,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( EEPROM_COMP_NAME );
+
+ break;
+ }
+
+ // EEPROM devices have write page boundaries, so when necessary
+ // need to split up command into multiple write operations
+
+ // Setup a max-size buffer of writePageSize
+ size_t newBufLen = i_i2cInfo.writePageSize;
+ newBuffer = static_cast<uint8_t*>(malloc( newBufLen ));
+ needFree = true;
+
+ // Point a uint8_t ptr at io_buffer for array addressing below
+ uint8_t * l_data_ptr = reinterpret_cast<uint8_t*>(io_buffer);
+
+ // Lock for operation sequencing
+ mutex_lock( &g_eepromMutex );
+ unlock = true;
+
+ // variables to store different amount of data length
+ size_t loop_data_length = 0;
+ size_t total_bytes_written = 0;
+
+ while( total_bytes_written < io_buflen )
+ {
+ // Determine how much data can be written in this loop
+ // Can't go over a writePageSize boundary
+
+ // Total data left to write
+ data_left = io_buflen - total_bytes_written;
+
+ // Difference to next writePageSize boundary
+ diff_wps = i_i2cInfo.writePageSize -
+ (i_i2cInfo.offset % i_i2cInfo.writePageSize);
+
+ // Take the lesser of the 2 options
+ loop_data_length = (data_left < diff_wps ) ? data_left : diff_wps;
+
+ // Add the data the user wanted to write
+ memcpy( newBuffer,
+ &l_data_ptr[total_bytes_written],
+ loop_data_length );
+
+
+
+ // Check if loop_data_length crosses the EEPROM page boundary
+ crossesEepromPageBoundary( i_i2cInfo.offset,
+ loop_data_length,
+ l_writeBuflen,
+ l_bytesIntoSecondPage,
+ i_i2cInfo );
+
+ // Setup offset/address parms
+ err = eepromPrepareAddress( i_target,
+ &byteAddr,
+ byteAddrSize,
+ l_desiredPage,
+ i_i2cInfo );
+
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"eepromWrite::eepromPrepareAddress()::loop version");
+ break;
+ }
+
+
+
+ // if desired page has changed mid-request, switch to correct page
+ if( l_desiredPage != l_originalPage )
+ {
+ l_switchPage = true;
+ l_lockMutex = false;
+ err = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+ if( err )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "Failed switching to new EEPROM page!");
+ break;
+ }
+ l_originalPage = l_desiredPage;
+ }
+
+ TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop: %d/%d/0x%X "
+ "writeBuflen=%d, offset=0x%X, bAS=%d, diffs=%d/%d",
+ i_i2cInfo.port, i_i2cInfo.engine, i_i2cInfo.devAddr,
+ l_writeBuflen, i_i2cInfo.offset, byteAddrSize,
+ data_left, diff_wps);
+
+ // Perform the requested write operation
+ err = eepromWriteData( i_target,
+ newBuffer,
+ l_writeBuflen,
+ &byteAddr,
+ byteAddrSize,
+ i_i2cInfo );
+
+ if ( err )
+ {
+ // Can't assume that anything was written if
+ // there was an error, so no update to total_bytes_written
+ // for this loop
+ TRACFCOMP(g_trac_eeprom,
+ "Failed writing data: original eeprom write");
+ break;
+ }
+
+ // Wait for EEPROM to write data to its internal memory
+ // i_i2cInfo.writeCycleTime value in milliseconds
+ nanosleep( 0, i_i2cInfo.writeCycleTime * NS_PER_MSEC );
+
+ // Update how much data was written
+ total_bytes_written += l_writeBuflen;
+
+ // Update offset
+ i_i2cInfo.offset += l_writeBuflen;
+
+ TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop End: "
+ "writeBuflen=%d, offset=0x%X, t_b_w=%d, io_buflen=%d",
+ l_writeBuflen, i_i2cInfo.offset,
+ total_bytes_written, io_buflen);
+ } // end of write for-loop
+
+ // Release mutex lock
+ mutex_unlock( &g_eepromMutex );
+ unlock = false;
+
+
+ // Set how much data was actually written
+ io_buflen = total_bytes_written;
+
+
+ TRACSCOMP( g_trac_eeprom,
+ "EEPROM WRITE END : Eeprom Role : %02d : Offset %.2X : Len %d",
+ i_i2cInfo.eepromRole, i_i2cInfo.offset, io_buflen );
+ } while( 0 );
+
+ // Free memory
+ if( needFree )
+ {
+ free( newBuffer );
+ }
+
+ // Catch it if we break out early.
+ if( unlock )
+ {
+ mutex_unlock( & g_eepromMutex );
+ }
+
+
+ // Whether we failed in the main routine or not, unlock the page iff it is already
+ // locked
+ if( l_pageLocked )
+ {
+ errlHndl_t l_pageOpErrl = NULL;
+
+ bool l_switchPage = false;
+ bool l_lockMutex = false;
+ l_pageOpErrl = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+ if( l_pageOpErrl )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "eepromWrite()::Failed unlocking page");
+ errlCommit(l_pageOpErrl, I2C_COMP_ID);
+ }
+
+ }
+
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromWrite()" );
+
+ return err;
+
+} // end eepromWrite
+
+
+
+// ------------------------------------------------------------------
+// eepromWriteData
+// ------------------------------------------------------------------
+errlHndl_t eepromWriteData( TARGETING::Target * i_target,
+ void * i_dataToWrite,
+ size_t i_dataLen,
+ void * i_byteAddress,
+ size_t i_byteAddressSize,
+ eeprom_addr_t i_i2cInfo )
+{
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromWriteData()");
+ errlHndl_t err = NULL;
+ errlHndl_t err_retryable = NULL;
+ do
+ {
+ /***********************************************************/
+ /* Attempt write multiple times ONLY on retryable fails */
+ /***********************************************************/
+ for (uint8_t retry = 0;
+ retry <= EEPROM_MAX_RETRIES;
+ retry++)
+ {
+ // Do the actual data write
+ err = deviceOp( DeviceFW::WRITE,
+ i_target,
+ i_dataToWrite,
+ i_dataLen,
+ DEVICE_I2C_ADDRESS_OFFSET(
+ i_i2cInfo.port,
+ i_i2cInfo.engine,
+ i_i2cInfo.devAddr,
+ i_byteAddressSize,
+ reinterpret_cast<uint8_t*>(
+ i_byteAddress),
+ i_i2cInfo.i2cMuxBusSelector,
+ &(i_i2cInfo.i2cMuxPath) ) );
+
+ if ( err == NULL )
+ {
+ // Operation completed successfully
+ // break from retry loop
+ break;
+ }
+ else if ( !errorIsRetryable( err->reasonCode() ) )
+ {
+ // Only retry on errorIsRetryable() failures: break from retry loop
+ TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData(): I2C "
+ "Write Non-Retryable fail %d/%d/0x%X, "
+ "ldl=%d, offset=0x%X, aS=%d, retry=%d",
+ i_i2cInfo.port, i_i2cInfo.engine,
+ i_i2cInfo.devAddr, i_dataLen,
+ i_i2cInfo.offset, i_i2cInfo.addrSize, retry);
+
+ err->collectTrace(EEPROM_COMP_NAME);
+
+ // break from retry loop
+ break;
+ }
+ else // Handle retryable error
+ {
+ TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData(): I2C "
+ "Write retryable fail %d/%d/0x%X, "
+ "ldl=%d, offset=0x%X, aS=%d, writePageSize = %x",
+ i_i2cInfo.port, i_i2cInfo.engine,
+ i_i2cInfo.devAddr, i_dataLen,
+ i_i2cInfo.offset, i_i2cInfo.addrSize,
+ i_i2cInfo.writePageSize);
+
+ // Printing mux info separately, if combined, nothing is displayed
+ char* l_muxPath = i_i2cInfo.i2cMuxPath.toString();
+ TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData():"
+ "muxSelector=0x%X, muxPath=%s",
+ i_i2cInfo.i2cMuxBusSelector,
+ l_muxPath);
+ free(l_muxPath);
+ l_muxPath = nullptr;
+
+ // If op will be attempted again: save error and continue
+ if ( retry < EEPROM_MAX_RETRIES )
+ {
+ // Only save original retryable error
+ if ( err_retryable == NULL )
+ {
+ // Save original retryable error
+ err_retryable = err;
+
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): "
+ "Error rc=0x%X, eid=0x%X plid=0x%X, "
+ "tgt=0x%X, retry/MAX=%d/%d. Save error "
+ "and retry",
+ err_retryable->reasonCode(),
+ err_retryable->eid(),
+ err_retryable->plid(),
+ TARGETING::get_huid(i_target),
+ retry, EEPROM_MAX_RETRIES);
+
+ err_retryable->collectTrace(EEPROM_COMP_NAME);
+ }
+ else
+ {
+ // Add data to original retryable error
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): "
+ "Another Retryable Error rc=0x%X, eid=0x%X "
+ "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. "
+ "Delete error and retry",
+ err->reasonCode(), err->eid(),
+ err->plid(),
+ TARGETING::get_huid(i_target),
+ retry, EEPROM_MAX_RETRIES);
+
+ ERRORLOG::ErrlUserDetailsString(
+ "Another retryable ERROR found")
+ .addToLog(err_retryable);
+
+ // Delete this new retryable error
+ delete err;
+ err = NULL;
+ }
+
+ // continue to retry
+ continue;
+ }
+ else // no more retries: trace and break
+ {
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): "
+ "Error rc=0x%X, tgt=0x%X. No More Retries "
+ "(retry/MAX=%d/%d). Returning Error",
+ err->reasonCode(),
+ TARGETING::get_huid(i_target),
+ retry, EEPROM_MAX_RETRIES);
+
+ err->collectTrace(EEPROM_COMP_NAME);
+
+ // break from retry loop
+ break;
+ }
+ }
+
+ } // end of retry loop
+ /***********************************************************/
+
+ // Handle saved retryable errors, if any
+ if (err_retryable)
+ {
+ if (err)
+ {
+ // commit original retryable error with new err PLID
+ err_retryable->plid(err->plid());
+ TRACFCOMP(g_trac_eeprom, "eepromWriteData(): Committing saved "
+ "retryable err eid=0x%X with plid of returned err: "
+ "0x%X",
+ err_retryable->eid(), err_retryable->plid());
+
+ ERRORLOG::ErrlUserDetailsTarget(i_target)
+ .addToLog(err_retryable);
+
+ errlCommit(err_retryable, EEPROM_COMP_ID);
+ }
+ else
+ {
+ // Since we eventually succeeded, delete original retryable error
+ TRACFCOMP(g_trac_eeprom, "eepromWriteData(): Op successful, "
+ "deleting saved retryable err eid=0x%X, plid=0x%X",
+ err_retryable->eid(), err_retryable->plid());
+
+ delete err_retryable;
+ err_retryable = NULL;
+ }
+ }
+ }while( 0 );
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromWriteData()");
+ return err;
+}
+
+
+
+// ------------------------------------------------------------------
+// eepromPrepareAddress
+// ------------------------------------------------------------------
+errlHndl_t eepromPrepareAddress ( TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t & o_bufSize,
+ uint8_t & o_desiredPage,
+ const eeprom_addr_t & i_i2cInfo )
+{
+ errlHndl_t err = NULL;
+ o_bufSize = 0;
+
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromPrepareAddress()" );
+
+ do
+ {
+
+ // --------------------------------------------------------------------
+ // Currently only supporting I2C devices and that use 0, 1, or 2 bytes
+ // to set the offset (ie, internal address) into the device.
+ // --------------------------------------------------------------------
+ switch( i_i2cInfo.addrSize )
+ {
+ case TWO_BYTE_ADDR:
+ o_bufSize = 2;
+ memset( io_buffer, 0x0, o_bufSize );
+ *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFF00ull) >> 8;
+ *((uint8_t*)io_buffer+1) = (i_i2cInfo.offset & 0x00FFull);
+ break;
+
+ case ONE_BYTE_ADDR_PAGESELECT:
+ // If the offset is less than 256 bytes, report page zero, else page 1
+ if( i_i2cInfo.offset >= EEPROM_PAGE_SIZE )
+ {
+ o_desiredPage = 1;
+ }
+ else
+ {
+ o_desiredPage = 0;
+ }
+ o_bufSize = 1;
+ memset( io_buffer, 0x0, o_bufSize );
+ *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFFull);
+ break;
+
+ case ONE_BYTE_ADDR:
+ o_bufSize = 1;
+ memset( io_buffer, 0x0, o_bufSize );
+ *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFFull);
+ break;
+
+ case ZERO_BYTE_ADDR:
+ o_bufSize = 0;
+ // nothing to do with the buffer in this case
+ break;
+
+ default:
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromPrepareAddress() - Invalid Device "
+ "Address Size: 0x%08x", i_i2cInfo.addrSize);
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_INVALID_DEVICE_TYPE
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_PREPAREADDRESS
+ * @userdata1 Address Size (aka Device Type)
+ * @userdata2 EEPROM chip
+ * @devdesc The Device type not supported (addrSize)
+ * @custdesc A problem was detected during the IPL of
+ * the system: Device type not supported.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_PREPAREADDRESS,
+ EEPROM_INVALID_DEVICE_TYPE,
+ i_i2cInfo.addrSize,
+ i_i2cInfo.eepromRole,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( EEPROM_COMP_NAME );
+
+ break;
+ }
+
+ } while( 0 );
+
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromPrepareAddress()" );
+
+ return err;
+} // end eepromPrepareAddress
+
+} \ No newline at end of file
diff --git a/src/usr/i2c/eepromdd.H b/src/usr/i2c/eepromdd_hardware.H
index 8acf7d8f2..38c7a4d58 100755..100644
--- a/src/usr/i2c/eepromdd.H
+++ b/src/usr/i2c/eepromdd_hardware.H
@@ -1,11 +1,11 @@
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
-/* $Source: src/usr/i2c/eepromdd.H $ */
+/* $Source: src/usr/i2c/eepromdd_hardware.H $ */
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2019 */
+/* Contributors Listed Below - COPYRIGHT 2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -22,86 +22,31 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
-#ifndef __EEPROM_H
-#define __EEPROM_H
+#ifndef __EEPROMDD_HARDWARE_H
+#define __EEPROMDD_HARDWARE_H
/**
- * @file eepromdd.H
+ * @file eepromdd_hardware.H
*
* @brief Provides the interfaces for accessing EEPROMs within
- * the system via the I2C device driver.
+ * the system via the I2C device driver
*/
-// ----------------------------------------------
-// Includes
-// ----------------------------------------------
-#include <i2c/eepromif.H>
+#include <i2c/eeprom_const.H>
#include <errl/errlentry.H>
-namespace EEPROM
-{
-
-/**
-* @brief Enumerations to describe the type of devices to be accessed.
-*/
-typedef enum
-{
- ZERO_BYTE_ADDR = 0,
- ONE_BYTE_ADDR_PAGESELECT = 1, // page select
- TWO_BYTE_ADDR = 2,
- ONE_BYTE_ADDR = 3,
- LAST_DEVICE_TYPE
-} eeprom_addr_size_t;
-/**
- * @brief Structure of common parameters needed by different parts of
- * the code.
- */
-struct eeprom_addr_t
+namespace EEPROM
{
- uint64_t port;
- uint64_t engine;
- uint64_t devAddr;
- int64_t eepromRole;
- uint64_t offset;
- eeprom_addr_size_t addrSize;
- TARGETING::EntityPath i2cMasterPath;
- uint64_t writePageSize; // in bytes
- uint64_t devSize_KB; // in kilobytes
- uint64_t chipCount; // number of chips making up eeprom device
- uint64_t writeCycleTime; // in milliseconds
- uint8_t i2cMuxBusSelector;
- TARGETING::EntityPath i2cMuxPath;
-
- /**
- * @brief Construct a default eeprom_addr_t
- */
- eeprom_addr_t()
- : port(0),
- engine(0),
- devAddr(0),
- eepromRole(0),
- offset(0),
- addrSize(LAST_DEVICE_TYPE),
- i2cMasterPath(),
- writePageSize(0),
- devSize_KB(0),
- chipCount(0),
- writeCycleTime(0),
- i2cMuxBusSelector(I2C_MUX::NOT_APPLICABLE),
- i2cMuxPath()
- {
- }
-};
/**
*
-* @brief Perform an EEPROM access operation.
+* @brief Perform an EEPROM access operation on the actual hardware.
*
* @param[in] i_opType - Operation Type - See DeviceFW::OperationType in
* driververif.H
*
-* @param[in] i_target - Target device.
+* @param[in] i_target - Target device associated w/ the EEPROM.
*
* @param[in/out] io_buffer
* INPUT: Pointer to the data that will be written to the target
@@ -113,24 +58,22 @@ struct eeprom_addr_t
* OUTPUT: Length of buffer that was written, or length of buffer
* to be read from target device.
*
-* @param [in] i_accessType - Access Type - See DeviceFW::AccessType in
-* usrif.H
+* @param [in/out] io_i2cInfo struct containing information needed to perform
+* operation on the given i2c eeprom. NOTE It is expected that
+* eepromRole and offset have been filled out in this struct
+* prior to passing it into this function
*
-* @param [in] i_args - This is an argument list for the device driver
-* framework. This argument list consists of the chip number of
-* the EEPROM to access from the given I2C Master target and the
-* internal offset to use on the slave I2C device.
+* @pre It is expected that io_i2cInfo.eepromRole will have a valid role set
*
-* @return errlHndl_t - NULL if successful, otherwise a pointer to the
+* @return errlHndl_t - nullptr if successful, otherwise a pointer to the
* error log.
*
*/
-errlHndl_t eepromPerformOp( 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 eepromPerformOpHW(DeviceFW::OperationType i_opType,
+ TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t & io_buflen,
+ eeprom_addr_t & io_i2cInfo) ;
/**
*
@@ -146,7 +89,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
* @param[in/out] i_pageLocked - bool to tell the caller if the page
* was successfully locked.
* @param[in] i_desiredPage - The page we want to switch to
- * @param[in] i_args - This is an argument list for the device driver
+ * @param[in] i_i2cInfo - This is an argument list for the device driver
* framework. This argument list consists of the chip number of
* the EEPROM to access from the given I2C Master target and the
* internal offset to use on the slave I2C device.
@@ -159,10 +102,10 @@ errlHndl_t eepromPageOp( TARGETING::Target * i_target,
bool i_lockMutex,
bool & io_pageLocked,
uint8_t i_desiredPage,
- eeprom_addr_t i_i2cInfo );
+ const eeprom_addr_t & i_i2cInfo );
-/*
+/**
* @brief This utility function determines if a read/write straddles
* the boundary between EEPROM pages and if so, returns the
* parameters to perform 2 operations, one for each page.
@@ -183,7 +126,7 @@ bool crossesEepromPageBoundary( uint64_t i_originalOffset,
size_t i_originalLen,
size_t & io_newLen,
size_t & o_pageTwoBuflen,
- eeprom_addr_t i_i2cInfo );
+ const eeprom_addr_t & i_i2cInfo );
/**
@@ -309,48 +252,8 @@ errlHndl_t eepromPrepareAddress ( TARGETING::Target * i_target,
void * io_buffer,
size_t & o_bufSize,
uint8_t & o_desiredPage,
- eeprom_addr_t i_i2cInfo);
-
-/**
- * @brief this function will read all of the associated attributes needed
- * to access the intended EEPROM. These attributes will be used to
- * determine the type of I2C device as well as how to address it via
- * the I2C device driver.
- *
- * @param[in] i_target - Target device.
- *
- * @param[out] o_i2cInfo - The structure that will contain the attribute data
- * read from the target device.
- *
- * @return errlHndl_t - NULL if successful, otherwise a pointer to the
- * error log.
- */
-errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
- eeprom_addr_t & o_i2cInfo );
-
-/**
- * @brief This function decides whether or not the target passed into the
- * EEPROM device driver actually contains the I2C Master engines. If
- * not, it will then read the attribute of the target to get the path
- * of the target which does contain the I2C Master engine.
- *
- * @param[in] i_target - The current Target.
- *
- * @param[in] i_i2cInfo - Structure of I2C parameters needed to execute
- * the command to the I2C device driver.
- *
- * @param[out] o_target - The "new" target that will be used for all operations
- * from this point on. It may be == to i_target, or a completely different
- * target. BUT, this target will contain the I2C Master engine that will
- * allow operations to the target EEPROM.
- *
- * @return errlHndl_t - NULL if successful, otherwise a pointer to the
- * error log.
- */
-errlHndl_t eepromGetI2CMasterTarget ( TARGETING::Target * i_target,
- eeprom_addr_t i_i2cInfo,
- TARGETING::Target * &o_target );
+ const eeprom_addr_t & i_i2cInfo);
-}; // end EEPROM namespace
+}
-#endif // __EEPROM_H
+#endif \ No newline at end of file
diff --git a/src/usr/i2c/errlud_i2c.C b/src/usr/i2c/errlud_i2c.C
index bd27be102..121905e5c 100644
--- a/src/usr/i2c/errlud_i2c.C
+++ b/src/usr/i2c/errlud_i2c.C
@@ -32,7 +32,6 @@
#include <i2c/i2creasoncodes.H>
#include <i2c/eepromddreasoncodes.H>
#include <devicefw/driverif.H>
-#include "eepromdd.H"
#include "i2c.H"
namespace I2C
diff --git a/src/usr/i2c/errlud_i2c.H b/src/usr/i2c/errlud_i2c.H
index 28e8c230d..fb9e752f2 100644
--- a/src/usr/i2c/errlud_i2c.H
+++ b/src/usr/i2c/errlud_i2c.H
@@ -34,8 +34,7 @@
#include <errl/errluserdetails.H>
#include <devicefw/driverif.H>
#include "i2c_common.H"
-#include "eepromdd.H"
-
+#include <i2c/eeprom_const.H>
namespace I2C
{
diff --git a/src/usr/i2c/i2c.mk b/src/usr/i2c/i2c.mk
index 33d2accda..6d4ef8935 100644
--- a/src/usr/i2c/i2c.mk
+++ b/src/usr/i2c/i2c.mk
@@ -24,4 +24,7 @@
# IBM_PROLOG_END_TAG
# common objects with runtime
OBJS += eepromdd.o
+OBJS += eepromdd_hardware.o
+OBJS += eeprom_utils.o
OBJS += errlud_i2c.o
+OBJS += $(if $(CONFIG_SUPPORT_EEPROM_CACHING),eepromCache.o)
diff --git a/src/usr/i2c/makefile b/src/usr/i2c/makefile
index 10e55c9de..535484752 100644
--- a/src/usr/i2c/makefile
+++ b/src/usr/i2c/makefile
@@ -33,7 +33,6 @@ OBJS += i2c.o
OBJS += $(if $(CONFIG_TPMDD),tpmdd.o,)
OBJS += fapi_i2c_dd.o
OBJS += i2cTargetPres.o
-OBJS += $(if $(CONFIG_SUPPORT_EEPROM_CACHING),eepromCache.o)
SUBDIRS += test.d
SUBDIRS += runtime.d
diff --git a/src/usr/i2c/test/eepromddtest.H b/src/usr/i2c/test/eepromddtest.H
index 228c0090c..683b2cdb3 100755
--- a/src/usr/i2c/test/eepromddtest.H
+++ b/src/usr/i2c/test/eepromddtest.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2017 */
+/* Contributors Listed Below - COPYRIGHT 2011,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -37,10 +37,11 @@
#include <errl/errlentry.H>
#include <devicefw/driverif.H>
#include <i2c/eepromddreasoncodes.H>
+#include <i2c/eeprom_const.H>
+#include <i2c/eepromif.H>
#include <targeting/common/commontargeting.H>
#include <pnor/pnorif.H>
#include "i2ctest.H"
-#include "../eepromdd.H"
#include <secureboot/service.H>
@@ -183,7 +184,8 @@ class EEPROMTest: public CxxTest::TestSuite
testData[i].size,
DEVICE_EEPROM_ADDRESS(
testData[i].chip,
- testData[i].offset));
+ testData[i].offset,
+ EEPROM::AUTOSELECT));
if( err )
{
@@ -367,7 +369,8 @@ class EEPROMTest: public CxxTest::TestSuite
testBuffer,
testBufLen,
DEVICE_EEPROM_ADDRESS(SBE_BACKUP,
- offset));
+ offset,
+ EEPROM::AUTOSELECT));
if( err )
{
@@ -503,7 +506,8 @@ class EEPROMTest: public CxxTest::TestSuite
&data,
dataSize,
DEVICE_EEPROM_ADDRESS( 0x0,
- 0x0 ) );
+ 0x0 ,
+ EEPROM::AUTOSELECT) );
if( NULL == err )
{
@@ -567,7 +571,8 @@ class EEPROMTest: public CxxTest::TestSuite
&data,
dataSize,
DEVICE_EEPROM_ADDRESS( 0x0,
- offset ) );
+ offset,
+ EEPROM::AUTOSELECT) );
if( NULL == err )
{
@@ -630,7 +635,8 @@ class EEPROMTest: public CxxTest::TestSuite
&data,
dataSize,
DEVICE_EEPROM_ADDRESS( LAST_CHIP_TYPE,
- 0x0 ) );
+ 0x0,
+ EEPROM::AUTOSELECT) );
if( NULL == err )
{
OpenPOWER on IntegriCloud