summaryrefslogtreecommitdiffstats
path: root/src/usr/i2c
diff options
context:
space:
mode:
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