summaryrefslogtreecommitdiffstats
path: root/src/usr/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/i2c')
-rw-r--r--src/usr/i2c/eepromCache.C812
-rw-r--r--src/usr/i2c/eepromCache.H157
-rw-r--r--src/usr/i2c/eepromCache_common.C325
-rw-r--r--src/usr/i2c/eeprom_utils.C14
-rwxr-xr-xsrc/usr/i2c/eepromdd.C73
-rw-r--r--src/usr/i2c/eepromdd_hardware.C16
-rw-r--r--src/usr/i2c/fapi_i2c_dd.C74
-rwxr-xr-xsrc/usr/i2c/i2c.C138
-rwxr-xr-xsrc/usr/i2c/i2c.H4
-rw-r--r--src/usr/i2c/i2c.mk4
-rw-r--r--src/usr/i2c/i2cTargetPres.C127
-rw-r--r--src/usr/i2c/makefile1
-rw-r--r--src/usr/i2c/runtime/makefile6
-rw-r--r--src/usr/i2c/runtime/rt_eepromCache.C285
-rwxr-xr-xsrc/usr/i2c/runtime/rt_i2c.C8
-rw-r--r--src/usr/i2c/test/eecachetest.H121
-rw-r--r--src/usr/i2c/test/makefile3
-rwxr-xr-xsrc/usr/i2c/test/tpmddtest.H36
-rwxr-xr-xsrc/usr/i2c/tpmdd.C3
19 files changed, 1757 insertions, 450 deletions
diff --git a/src/usr/i2c/eepromCache.C b/src/usr/i2c/eepromCache.C
index ef906302c..bbdddf334 100644
--- a/src/usr/i2c/eepromCache.C
+++ b/src/usr/i2c/eepromCache.C
@@ -30,17 +30,18 @@
#include <devicefw/driverif.H>
#include <errl/errlmanager.H>
#include <fsi/fsiif.H>
+#include <hwas/hwasPlat.H>
#include "i2c.H"
#include "eepromCache.H"
#include <i2c/i2cif.H>
-#include <i2c/eepromif.H>
+
#include <i2c/eepromddreasoncodes.H>
#include <initservice/initserviceif.H>
#include <initservice/initsvcreasoncodes.H>
#include <pnor/pnorif.H>
#include <vpd/vpd_if.H>
+
#include <errl/errludtarget.H>
-#include <config.h>
#ifdef CONFIG_CONSOLE
#include <console/consoleif.H>
#endif
@@ -53,6 +54,10 @@ extern trace_desc_t* g_trac_eeprom;
namespace EEPROM
{
+// Any time we access either any of the global variables defined below we want
+// to wrap the call in this mutex to avoid multi-threading issues
+mutex_t g_eecacheMutex = MUTEX_INITIALIZER;
+
// 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
@@ -63,166 +68,10 @@ 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;
-
-uint64_t lookupEepromAddr(const eepromRecordHeader& i_eepromRecordHeader)
-{
- 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(l_it != g_cachedEeproms.end())
- {
- l_vaddr = l_it->second;
- }
-
- if(l_vaddr == 0)
- {
- TRACSSCOMP( g_trac_eeprom, "lookupEepromAddr() failed to find I2CM Huid: 0x%.08X, Port: 0x%.02X, Engine: 0x%.02X, Dev Addr: 0x%.02X, Mux Select: 0x%.02X, Size: 0x%.08X in 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);
- }
- return l_vaddr;
-}
-
-errlHndl_t buildEepromRecordHeader(TARGETING::Target * i_target,
- eeprom_addr_t & io_eepromInfo,
- eepromRecordHeader & o_eepromRecordHeader)
-{
-
- TARGETING::Target * l_muxTarget = nullptr;
- TARGETING::Target * l_i2cMasterTarget = nullptr;
- TARGETING::TargetService& l_targetService = TARGETING::targetService();
- errlHndl_t l_errl = nullptr;
-
- do{
-
- l_errl = eepromReadAttributes(i_target, io_eepromInfo);
- if(l_errl)
- {
- 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(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( io_eepromInfo.i2cMuxPath);
- if(l_muxTarget == nullptr)
- {
- 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),
- io_eepromInfo.eepromRole);
- /*@
- * @errortype
- * @moduleid EEPROM_CACHE_EEPROM
- * @reasoncode EEPROM_I2C_MUX_PATH_ERROR
- * @userdata1 HUID of target we want to cache
- * @userdata2 Type of EEPROM we are caching
- * @devdesc buildEepromRecordHeader invalid mux target
- */
- l_errl = new ERRORLOG::ErrlEntry(
- ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_CACHE_EEPROM,
- EEPROM_I2C_MUX_PATH_ERROR,
- TARGETING::get_huid(i_target),
- io_eepromInfo.eepromRole,
- ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
- 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( io_eepromInfo.i2cMasterPath );
- if(l_i2cMasterTarget == nullptr)
- {
- 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),
- io_eepromInfo.eepromRole);
- /*@
- * @errortype
- * @moduleid EEPROM_CACHE_EEPROM
- * @reasoncode EEPROM_I2C_MASTER_PATH_ERROR
- * @userdata1 HUID of target we want to cache
- * @userdata2 Type of EEPROM we are caching
- * @devdesc buildEepromRecordHeader invalid master target
- */
- l_errl = new ERRORLOG::ErrlEntry(
- ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- EEPROM_CACHE_EEPROM,
- EEPROM_I2C_MASTER_PATH_ERROR,
- TARGETING::get_huid(i_target),
- io_eepromInfo.eepromRole,
- ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
- 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;
-}
+// Value = A struct of 2 uint64_t virtual addresses ,one points to header address
+// and other points to the location of the cache, and a byte indicating
+// if this eeprom's hardware has changed this IPL
+std::map<eepromRecordHeader, EeepromEntryMetaData_t> g_cachedEeproms;
/**
* @brief Lookup I2C information for given eeprom, check if eeprom exists in cache.
@@ -252,13 +101,19 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
bool l_updateHeader = true;
bool l_updateContents = true;
+ // Initially assume this is a new eeprom cache entry
+ bool l_newEntryDetected = 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;
+ if(i_present)
+ {
+ l_eepromRecordHeader.completeRecord.cached_copy_valid = 1;
+ }
// buildEepromRecordHeader will call eepromReadAttributes to fill in l_eepromInfo
// with info looked up in attributes and also fill in l_eepromRecordHeader
@@ -271,7 +126,7 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
if(l_errl)
{
// buildEepromRecordHeader should have traced any relavent information if
- // is was needed, just break out and pass the error along
+ // it was needed, just break out and pass the error along
break;
}
@@ -310,7 +165,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_eeprom,
+ TRACDCOMP( g_trac_eeprom,
"cacheEeprom() Found Empty Cache, set version of cache structure to be 0x%.02x",
EECACHE_VERSION_1);
}
@@ -322,7 +177,7 @@ 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_eeprom,
+ TRACDCOMP( g_trac_eeprom,
"cacheEeprom() Found Empty Cache, set end of cache to be 0x%.04x (End of ToC)",
sizeof(eecacheSectionHeader));
}
@@ -356,6 +211,9 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
// 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;
+
+ // Set cached_copy_valid to 0 until the cache contents actually gets loaded
+ l_recordHeaderToUpdate->completeRecord.cached_copy_valid = 0;
l_updateContents = i_present;
break;
}
@@ -366,6 +224,9 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
if( memcmp(l_recordHeaderToUpdate, &l_eepromRecordHeader, NUM_BYTE_UNIQUE_ID ) == 0 )
{
l_recordHeaderToUpdateIndex = i;
+ // We have matched with existing eeprom in the PNOR's EECACHE
+ // section. So we know this is not a new entry.
+ l_newEntryDetected = false;
if( l_recordHeaderToUpdate->completeRecord.cache_copy_size != l_eepromRecordHeader.completeRecord.cache_copy_size)
{
@@ -410,81 +271,192 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
#ifdef CONFIG_CONSOLE
CONSOLE::displayf(EEPROM_COMP_NAME,
- "New EEPROM size detected for an existing part, clearing EEPROM cache and performing reconfig loop");
+ "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
+ // 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;
+ l_recordHeaderToUpdate->completeRecord.internal_offset;
+ TRACSSCOMP(g_trac_eeprom,
+ "cacheEeprom() already found copy for eeprom role %d "
+ "for target w/ HUID 0x.%08X in EECACHE table of contents",
+ i_eepromType , TARGETING::get_huid(i_target));
+ break;
+ }
+ }
- 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)
+ // pass the record we have been building up (l_eepromRecordHeader)
+ // and the virtual address of this eeprom's record entry in the
+ // EECACHE table of contents as a uint64.
+ if(!addEepromToCachedList(l_eepromRecordHeader,
+ reinterpret_cast<uint64_t>(l_recordHeaderToUpdate)))
+ {
+ TRACSSCOMP( g_trac_eeprom,
+ "cacheEeprom() Eeprom w/ Role %d, HUID 0x.%08X added to the global map of cached eeproms",
+ i_eepromType , TARGETING::get_huid(i_target));
+ }
+ else
+ {
+ // If this target's eeprom has already been cached in PNOR and our global map
+ // indicates the cache entry was updated this boot, then we must also
+ // mark this target associated with the cached eeprom as changed for hwas
+ if( hasEeepromChanged( l_eepromRecordHeader ) )
+ {
+ HWAS::markTargetChanged(i_target);
+ }
+ TRACSSCOMP( g_trac_eeprom,
+ "cacheEeprom() Eeprom w/ Role %d, HUID 0x.%08X already in global map of cached eeproms",
+ i_eepromType , TARGETING::get_huid(i_target));
- // TODO RTC:203788 add lookup for PN and SN matches
- //if( !i_present || PNandSNMatch )
- {
- l_updateContents = false;
- }
+ // Cache entry has already been updated via another target, just break out
+ break;
+ }
- // If target is present there is nothing in the
- // header to update
- if( i_present )
- {
- l_updateHeader = false;
- }
+ // Only check if the cache is in sync with HARDWARE if there is an
+ // existing EECACHE section. Otherwise, the code after this logic will
+ // take care of adding a new eeprom cache section for the target.
+ if (l_recordHeaderToUpdate->completeRecord.cached_copy_valid)
+ {
+ // At this point we have found a match in the PNOR but we need
+ // to decide what all needs an update.
+
+ // Create namespace alias for targeting to reduce number of
+ // new lines required to be within line character limit.
+ namespace T = TARGETING;
+
+ // 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)
+ T::EEPROM_CONTENT_TYPE l_eepromContentType =
+ T::EEPROM_CONTENT_TYPE_RAW;
+
+ if (i_eepromType == EEPROM::VPD_PRIMARY)
+ {
+ auto l_eepromVpd =
+ i_target->getAttr<T::ATTR_EEPROM_VPD_PRIMARY_INFO>();
+
+ l_eepromContentType =
+ static_cast<T::EEPROM_CONTENT_TYPE>(
+ l_eepromVpd.eepromContentType);
+ }
+ else
+ {
+ auto l_eepromVpd =
+ i_target->getAttr<T::ATTR_EEPROM_VPD_BACKUP_INFO>();
+
+ l_eepromContentType =
+ static_cast<T::EEPROM_CONTENT_TYPE>(
+ l_eepromVpd.eepromContentType);
+ }
+
+
+ bool l_isInSync = false;
+
+ if (i_present)
+ {
+ l_errl = VPD::ensureEepromCacheIsInSync(i_target,
+ l_eepromContentType,
+ l_isInSync);
+
+ if (l_errl != nullptr)
+ {
+ break;
}
- else if(!i_present)
+
+ if(l_isInSync)
{
- // If the target is not present, then do not update contents or header
l_updateContents = false;
- l_updateHeader = false;
}
- 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;
}
- }
+ else
+ {
+ // Clear out the contents of the cache for this eeprom if we have detected that it
+ // was once valid, indicating it was present at one time, and is now showing
+ // up as not present. We want to clear the contents of cache so we can achieve
+ // the replug behavior where a tester can remove the part, boot, then plug in the
+ // same part and boot again fresh.
+ void * l_internalSectionAddr =
+ reinterpret_cast<uint8_t *>(l_eecacheSectionHeaderPtr) +
+ l_eepromRecordHeader.completeRecord.internal_offset;
+
+ memset( l_internalSectionAddr, 0xFF ,
+ (l_recordHeaderToUpdate->completeRecord.cache_copy_size * KILOBYTE));
+
+ l_updateContents = false;
+
+ setIsValidCacheEntry(l_eepromRecordHeader, false);
+
+ TRACFCOMP( g_trac_eeprom, "Detected Master 0x%.08X"
+ " Engine 0x%.02X Port 0x%.02X"
+ " MuxSelect 0x%.02X DevAddr 0x%.02X"
+ " no longer present, clearing cache and marking cache as invalid",
+ l_recordHeaderToUpdate->completeRecord.i2c_master_huid,
+ l_recordHeaderToUpdate->completeRecord.engine,
+ l_recordHeaderToUpdate->completeRecord.port,
+ l_recordHeaderToUpdate->completeRecord.mux_select,
+ l_recordHeaderToUpdate->completeRecord.devAddr);
+
+ setEeepromChanged(l_eepromRecordHeader);
+ // We have cleared the cache entry, this indicates we have found a part has been removed.
+ // Mark that the target is changed in hwas.
+ HWAS::markTargetChanged(i_target);
+ }
- if(!addEepromToCachedList(l_eepromRecordHeader))
+ // If target is present there is nothing in the
+ // header to update
+ if( i_present )
+ {
+ l_updateHeader = false;
+ }
+ }
+ else if(!i_present)
{
- TRACSSCOMP( g_trac_eeprom, "cacheEeprom() Eeprom w/ Role %d, HUID 0x.%08X added to cached list",
- i_eepromType , TARGETING::get_huid(i_target));
+ // If the target is not present, then do not update contents
+ l_updateContents = false;
+ // Only update header if this is a new entry
+ l_updateHeader = l_newEntryDetected;
}
- else
+ // The check below makes sure that is isnt a new entry
+ // If there is a matching header entry in PNOR marked 'invalid'
+ // but we now see the target as present, this indicates a replacement
+ // part has been added where a part was removed
+ else if(!l_newEntryDetected)
{
- TRACSSCOMP( g_trac_eeprom, "cacheEeprom() Eeprom w/ Role %d, HUID 0x.%08X already in cached list",
- i_eepromType , TARGETING::get_huid(i_target));
+ TRACFCOMP(g_trac_eeprom, "cacheEeprom() Detected replacement of a part"
+ " Master 0x%.08X Engine 0x%.02X"
+ " Port 0x%.02X MuxSelect 0x%.02X DevAddr 0x%.02X"
+ " that was previously removed, we will update the cache with new part's eeproms contents",
+ l_recordHeaderToUpdate->completeRecord.i2c_master_huid,
+ l_recordHeaderToUpdate->completeRecord.engine,
+ l_recordHeaderToUpdate->completeRecord.port,
+ l_recordHeaderToUpdate->completeRecord.mux_select,
+ l_recordHeaderToUpdate->completeRecord.devAddr);
}
-
// Above we have determined whether the contents of the eeprom at
// hand need to have their contents updated. Only do the following
// steps that update the eeprom's cached data if we were told to do so.
- if(l_updateContents )
+ if( l_updateContents )
{
assert(l_recordHeaderToUpdateIndex != INVALID_EEPROM_INDEX,
"More than MAX_EEPROMS_VERSION_1 in system XML");
+ TRACFCOMP( g_trac_eeprom, "cacheEeprom() updating cache entry");
+
void * l_tmpBuffer;
l_tmpBuffer = malloc(l_eepromLen);
void * l_internalSectionAddr =
- reinterpret_cast<uint8_t *>(l_eecacheSectionHeaderPtr) + l_eepromRecordHeader.completeRecord.internal_offset;
+ reinterpret_cast<uint8_t *>(l_eecacheSectionHeaderPtr) +
+ l_eepromRecordHeader.completeRecord.internal_offset;
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);
@@ -543,6 +515,18 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
break;
}
+ // Set mark_target_changed and cached_copy_valid and update set updateHeader
+ // Since we have copied stuff in the cache is valid, and been updated.
+ // Even if this is a replacement ( cached_copy_valid was already 1) we
+ // must set mark_target_changed so just always update the header
+ setEeepromChanged(l_eepromRecordHeader);
+ // We will update header in PNOR below so no need to call
+ // setIsValidCacheEntry right here
+ l_eepromRecordHeader.completeRecord.cached_copy_valid = 1;
+ l_updateHeader = true;
+ // We have updated the cache entry, this indicates we have found a "new" part.
+ // Mark that the target is changed in hwas.
+ HWAS::markTargetChanged(i_target);
}
// Above we have determined whether the header entry for the eeprom at
@@ -550,6 +534,7 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target,
// the eeprom's header entry if we were told to do so.
if(l_updateHeader)
{
+ TRACFCOMP( g_trac_eeprom, "cacheEeprom() updating header entry");
TRACDBIN( g_trac_eeprom, "cacheEeprom: l_eecacheSectionHeaderPtr currently ",
l_eecacheSectionHeaderPtr,
sizeof(eecacheSectionHeader));
@@ -658,175 +643,318 @@ DEVICE_REGISTER_ROUTE( DeviceFW::READ,
TARGETING::TYPE_DIMM,
genericI2CEepromCache );
-#endif
+DEVICE_REGISTER_ROUTE( DeviceFW::READ,
+ DeviceFW::EEPROM_CACHE,
+ TARGETING::TYPE_NODE,
+ genericI2CEepromCache );
-errlHndl_t eepromPerformOpCache(DeviceFW::OperationType i_opType,
- TARGETING::Target * i_target,
- void * io_buffer,
- size_t& io_buflen,
- eeprom_addr_t &i_eepromInfo)
+errlHndl_t setIsValidCacheEntry(const TARGETING::Target * i_target,
+ const EEPROM_ROLE &i_eepromRole,
+ bool i_isValid)
{
errlHndl_t l_errl = nullptr;
eepromRecordHeader l_eepromRecordHeader;
+ eeprom_addr_t l_eepromInfo;
do{
- TRACSSCOMP( g_trac_eeprom, ENTER_MRK"eepromPerformOpCache() "
- "Target HUID 0x%.08X Enter", TARGETING::get_huid(i_target));
+ TRACDCOMP( g_trac_eeprom, ENTER_MRK"setIsValidCacheEntry() "
+ "Target HUID 0x%.08X Eeprom Role = %d Enter",
+ TARGETING::get_huid(i_target), l_eepromInfo.eepromRole);
- l_errl = buildEepromRecordHeader(i_target, i_eepromInfo, l_eepromRecordHeader);
+ l_eepromInfo.eepromRole = i_eepromRole;
+ l_errl = buildEepromRecordHeader(const_cast<TARGETING::Target *>(i_target), l_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);
+ l_errl = setIsValidCacheEntry(l_eepromRecordHeader, i_isValid);
- // Ensure that a copy of the eeprom exists in our map of cached eeproms
- if(l_eepromCacheVaddr)
- {
- // First check if io_buffer is a nullptr, if so then assume user is
- // requesting size back in io_bufferlen
- if(io_buffer == nullptr)
- {
- io_buflen = l_eepromRecordHeader.completeRecord.cache_copy_size * KILOBYTE;
- TRACSSCOMP( g_trac_eeprom, "eepromPerformOpCache() "
- "io_buffer == nullptr , returning io_buflen as 0x%lx",
- io_buflen);
- break;
- }
+ }while(0);
- 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, io_buflen, l_eepromCacheVaddr);
+ return l_errl;
+}
- // Make sure that offset + buflen are less than the total size of the eeprom
- if(i_eepromInfo.offset + io_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(io_buflen),
- TO_UINT64(i_eepromInfo.offset),
- ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
- ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_errl);
- l_errl->collectTrace( EEPROM_COMP_NAME );
+errlHndl_t setIsValidCacheEntry(const eepromRecordHeader& i_eepromRecordHeader, bool i_isValid)
+{
+ errlHndl_t l_errl = nullptr;
+ eepromRecordHeader * l_eepromRecordHeaderToUpdate;
+ std::map<eepromRecordHeader, EeepromEntryMetaData_t>::iterator l_headerMapIterator;
- break;
- }
+ do{
- if(i_opType == DeviceFW::READ)
- {
- memcpy(io_buffer, reinterpret_cast<void *>(l_eepromCacheVaddr + i_eepromInfo.offset), io_buflen);
- }
- else if(i_opType == DeviceFW::WRITE)
- {
- memcpy(reinterpret_cast<void *>(l_eepromCacheVaddr + i_eepromInfo.offset), io_buffer, io_buflen);
+ TRACDCOMP( g_trac_eeprom, ENTER_MRK"setIsValidCacheEntry() ");
- #ifndef __HOSTBOOT_RUNTIME
- // Perform flush to ensure pnor is updated
- int rc = mm_remove_pages( FLUSH,
- reinterpret_cast<void *>(l_eepromCacheVaddr + i_eepromInfo.offset),
- io_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 );
- }
+ // Find the address of the header entry in the table of contents of the EECACHE pnor section
+ l_eepromRecordHeaderToUpdate =
+ reinterpret_cast<eepromRecordHeader *>(lookupEepromHeaderAddr(i_eepromRecordHeader));
+
+ if(l_eepromRecordHeaderToUpdate == 0)
+ {
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"setIsValidCacheEntry: Attempting to invalidate cache for an "
+ "eeprom but we could not find in global eecache map");
+ /*@
+ * @errortype
+ * @moduleid EEPROM_INVALIDATE_CACHE
+ * @reasoncode EEPROM_CACHE_NOT_FOUND_IN_MAP
+ * @userdata1[0:7] i2c_master_huid
+ * @userdata1[8:9] port on i2c master eeprom slave is on
+ * @userdata1[10:11] engine on i2c master eeprom slave is on
+ * @userdata1[12:13] devAddr of eeprom slave
+ * @userdata1[14:15] muxSelect of eeprom slave (0xFF is not valid)
+ * @userdata2[0:7] size of eeprom
+ * @devdesc invalidateCache failed to find cache in map
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_INVALIDATE_CACHE,
+ EEPROM_CACHE_NOT_FOUND_IN_MAP,
+ TWO_UINT32_TO_UINT64(
+ i_eepromRecordHeader.completeRecord.i2c_master_huid,
+ TWO_UINT16_TO_UINT32(
+ TWO_UINT8_TO_UINT16(
+ i_eepromRecordHeader.completeRecord.port,
+ i_eepromRecordHeader.completeRecord.engine),
+ TWO_UINT8_TO_UINT16(
+ i_eepromRecordHeader.completeRecord.devAddr,
+ i_eepromRecordHeader.completeRecord.mux_select))),
+ i_eepromRecordHeader.completeRecord.cache_copy_size,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ break;
}
- else
+
+ // Ensure that information at the address we just looked up matches the record we built up
+ if( memcmp(&l_eepromRecordHeaderToUpdate->uniqueRecord.uniqueID,
+ &i_eepromRecordHeader.uniqueRecord.uniqueID,
+ NUM_BYTE_UNIQUE_ID ) != 0 )
+ {
+ TRACFCOMP(g_trac_eeprom,ERR_MRK"setIsValidCacheEntry: Attempting to invalidate cache for an"
+ "eeprom but we could not find the entry in table of contents of EECACHE section of pnor");
+ /*@
+ * @errortype
+ * @moduleid EEPROM_INVALIDATE_CACHE
+ * @reasoncode EEPROM_CACHE_NOT_FOUND_IN_PNOR
+ * @userdata1[0:7] i2c_master_huid
+ * @userdata1[8:9] port on i2c master eeprom slave is on
+ * @userdata1[10:11] engine on i2c master eeprom slave is on
+ * @userdata1[12:13] devAddr of eeprom slave
+ * @userdata1[14:15] muxSelect of eeprom slave (0xFF is not valid)
+ * @userdata2[0:7] size of eeprom
+ * @devdesc invalidateCache failed to find cache in pnor
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_INVALIDATE_CACHE,
+ EEPROM_CACHE_NOT_FOUND_IN_PNOR,
+ TWO_UINT32_TO_UINT64(
+ i_eepromRecordHeader.completeRecord.i2c_master_huid,
+ TWO_UINT16_TO_UINT32(
+ TWO_UINT8_TO_UINT16(
+ i_eepromRecordHeader.completeRecord.port,
+ i_eepromRecordHeader.completeRecord.engine),
+ TWO_UINT8_TO_UINT16(
+ i_eepromRecordHeader.completeRecord.devAddr,
+ i_eepromRecordHeader.completeRecord.mux_select))),
+ i_eepromRecordHeader.completeRecord.cache_copy_size,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ break;
+ }
+
+ // Update the header so that it state the entry is invalid
+ l_eepromRecordHeaderToUpdate->completeRecord.cached_copy_valid = i_isValid;
+
+ // Flush the page to make sure it gets to the PNOR
+ int rc = mm_remove_pages( FLUSH,
+ l_eepromRecordHeaderToUpdate,
+ sizeof(eepromRecordHeader) );
+ if( rc )
{
- 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");
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"setIsValidCacheEntry: Error from mm_remove_pages trying for flush header write to pnor, rc=%d",rc);
/*@
* @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
+ * @moduleid EEPROM_INVALIDATE_CACHE
+ * @reasoncode EEPROM_FAILED_TO_FLUSH_HEADER
+ * @userdata1 Requested Address
+ * @userdata2 rc from mm_remove_pages
+ * @devdesc invalidateCache mm_remove_pages FLUSH failed
*/
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),
+ EEPROM_INVALIDATE_CACHE,
+ EEPROM_FAILED_TO_FLUSH_HEADER,
+ (uint64_t)l_eepromRecordHeaderToUpdate,
+ TO_UINT64(rc),
ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
- ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_errl);
- l_errl->collectTrace( EEPROM_COMP_NAME );
+ break;
}
- TRACSSCOMP( g_trac_eeprom, EXIT_MRK"eepromPerformOpCache() "
- "Target HUID 0x%.08X Exit", TARGETING::get_huid(i_target));
-
}while(0);
return l_errl;
}
+bool addEepromToCachedList(const eepromRecordHeader & i_eepromRecordHeader,
+ const uint64_t i_recordHeaderVaddr)
+{
+ bool l_matchFound = true;
+
+ // 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].cache_entry_address =
+ g_eecachePnorVaddr + i_eepromRecordHeader.completeRecord.internal_offset;
+
+ g_cachedEeproms[i_eepromRecordHeader].header_entry_address =
+ i_recordHeaderVaddr;
+
+ 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;
+}
+
+void printTableOfContents(void)
+{
+ eecacheSectionHeader * l_eecacheSectionHeaderPtr =
+ reinterpret_cast<eecacheSectionHeader*>(g_eecachePnorVaddr);
+
+ TRACFCOMP( g_trac_eeprom,
+ "printTableOfContents(): Version = 0x%.02X"
+ " End of Cache = 0x.08X",
+ l_eecacheSectionHeaderPtr->version,
+ l_eecacheSectionHeaderPtr->end_of_cache);
+
+ for(uint8_t i = 0; i < MAX_EEPROMS_VERSION_1; i++)
+ {
+ eepromRecordHeader l_currentRecordHeader =
+ l_eecacheSectionHeaderPtr->recordHeaders[i];
+
+ if( l_currentRecordHeader.completeRecord.internal_offset !=
+ UNSET_INTERNAL_OFFSET_VALUE)
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "printTableOfContents(): I2CM Huid: 0x%.08X, Port: 0x%.02X,"
+ " Engine: 0x%.02X, Dev Addr: 0x%.02X,"
+ " Mux Select: 0x%.02X, Size: 0x%.08X",
+ l_currentRecordHeader.completeRecord.i2c_master_huid,
+ l_currentRecordHeader.completeRecord.port,
+ l_currentRecordHeader.completeRecord.engine,
+ l_currentRecordHeader.completeRecord.devAddr,
+ l_currentRecordHeader.completeRecord.mux_select,
+ l_currentRecordHeader.completeRecord.cache_copy_size);
+
+ TRACFCOMP( g_trac_eeprom,
+ " "
+ "Internal Offset: 0x%.08X, Cache Valid: 0x%.02X",
+ l_currentRecordHeader.completeRecord.internal_offset,
+ l_currentRecordHeader.completeRecord.cached_copy_valid);
+ }
+ }
+
}
+
+bool hasEeepromChanged(const eepromRecordHeader & i_eepromRecordHeader)
+{
+ bool l_eepromHasChanged = false;
+
+ // 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())
+ {
+ l_eepromHasChanged = g_cachedEeproms[i_eepromRecordHeader].mark_target_changed;
+ }
+
+ mutex_unlock(&g_eecacheMutex);
+
+ return l_eepromHasChanged;
+}
+
+void setEeepromChanged(const eepromRecordHeader & i_eepromRecordHeader)
+{
+
+ // 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].mark_target_changed = true;
+ }
+
+ mutex_unlock(&g_eecacheMutex);
+
+}
+
+uint64_t lookupEepromCacheAddr(const eepromRecordHeader& i_eepromRecordHeader)
+{
+ uint64_t l_vaddr = 0;
+ std::map<eepromRecordHeader, EeepromEntryMetaData_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);
+
+ if(l_it != g_cachedEeproms.end())
+ {
+ l_vaddr = l_it->second.cache_entry_address;
+ }
+
+ mutex_unlock(&g_eecacheMutex);
+
+ return l_vaddr;
+}
+
+uint64_t lookupEepromHeaderAddr(const eepromRecordHeader& i_eepromRecordHeader)
+{
+ uint64_t l_vaddr = 0;
+ std::map<eepromRecordHeader, EeepromEntryMetaData_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);
+
+ if(l_it != g_cachedEeproms.end())
+ {
+ l_vaddr = l_it->second.header_entry_address;
+ }
+ mutex_unlock(&g_eecacheMutex);
+
+ if(l_vaddr == 0)
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "lookupEepromHeaderAddr() failed to find"
+ " I2CM Huid: 0x%.08X, Port: 0x%.02X,"
+ " Engine: 0x%.02X, Dev Addr: 0x%.02X,"
+ " Mux Select: 0x%.02X, Size: 0x%.08X"
+ "in 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);
+ }
+ return l_vaddr;
+}
+
+} \ No newline at end of file
diff --git a/src/usr/i2c/eepromCache.H b/src/usr/i2c/eepromCache.H
index 5cad475ba..253367b07 100644
--- a/src/usr/i2c/eepromCache.H
+++ b/src/usr/i2c/eepromCache.H
@@ -97,10 +97,44 @@ errlHndl_t buildEepromRecordHeader(TARGETING::Target * i_target,
eeprom_addr_t & io_eepromInfo,
eepromRecordHeader & o_eepromRecordHeader);
+
+#ifndef __HOSTBOOT_RUNTIME
+
+/**
+*
+* @brief Check if entry already exists in g_cachedEeproms, if a match is
+* found then return true. If there is no match, add it to the list
+* and return false;
+*
+* @param[in] i_eepromRecordHeader Header for record we want to add to map
+*
+* @param[in] i_recordHeaderVaddr Virtual address to PNOR copy of header information
+*
+* @return TRUE if entry is already in map FALSE if this is a new entry
+*
+*/
+bool addEepromToCachedList(const eepromRecordHeader & i_eepromRecordHeader,
+ const uint64_t i_recordHeaderVaddr);
+
+/**
+*
+* @brief Perform a lookup on the global map g_cachedEeproms to get a
+* virtual address for a given EEPROM entry in the EECACHE table of contents
+*
+* @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 lookupEepromHeaderAddr(const eepromRecordHeader& i_eepromRecordHeader);
+
/**
*
* @brief Perform a lookup on the global map g_cachedEeproms to get a
-* virtual address for a given EEPROM
+* virtual address for a given EEPROM cache entry
*
* @param[in] i_eepromRecordHeader
*
@@ -110,8 +144,127 @@ errlHndl_t buildEepromRecordHeader(TARGETING::Target * i_target,
* @return uint64_t virtual address pointing to the cached eeprom data in pnor
*
*/
-uint64_t lookupEepromAddr(const eepromRecordHeader & i_eepromRecordHeader);
+uint64_t lookupEepromCacheAddr(const eepromRecordHeader& i_eepromRecordHeader);
+
+/**
+*
+* @brief Print the info found in the Table of Contents of the EECACHE
+* section of pnor to trace buffer
+*
+* @return void
+*
+*/
+void printTableOfContents(void);
+
+
+/**
+*
+* @brief Update the record entry in the Table of Contents of the EECACHE
+* section of pnor to either mark the contents of the cache to be
+* valid or invalid
+*
+* @param[in] i_target Target associated with EEPROM
+*
+* @param[in] i_eepromRole Role of EEPROM associated with target (VPD_PRIMARY etc)
+*
+* @param[in] i_isValid Mark eeprom cache valid or invalid ?
+*
+* @return errlHndl_t - nullptr if successful, otherwise a pointer to the
+* error log.
+*
+*/
+errlHndl_t setIsValidCacheEntry(const TARGETING::Target * i_target,
+ const EEPROM_ROLE &i_eepromRole,
+ bool i_isValid);
+
+/**
+*
+* @brief Update the record entry in the Table of Contents of the EECACHE
+* section of pnor to either mark the contents of the cache to be
+* valid or invalid
+*
+* @param[in] i_eepromRecordHeader eepromRecord oject already filled in (including eepromRole)
+*
+* @param[in] i_isValid Mark eeprom cache valid or invalid ?
+*
+* @return errlHndl_t - nullptr if successful, otherwise a pointer to the
+* error log.
+*
+*/
+errlHndl_t setIsValidCacheEntry(const eepromRecordHeader& i_eepromRecordHeader, bool i_isValid);
+
+/**
+*
+* @brief Lookup a given i_eepromRecordHeader in the global map of eeprom
+* caches and check if the eeprom has changed this IPL or not
+*
+* @param[in] i_eepromRecordHeader we want to look up
+*
+* @return bool Return TRUE if eeprom is found in map AND mark_target_changed
+ was set to true for the eeprom entry. Return FALSE otherwise.
+*
+*/
+bool hasEeepromChanged(const eepromRecordHeader & i_eepromRecordHeader);
+
+/**
+*
+* @brief Lookup a given i_eepromRecordHeader in the global map of eeprom
+* caches and mark that it has changed this IPL
+*
+* @param[in] i_eepromRecordHeader we want to mark as changed
+*
+* @return void
+*/
+void setEeepromChanged(const eepromRecordHeader & i_eepromRecordHeader);
+#else
+/**
+*
+* @brief Check if entry already exists in g_cachedEeproms, if a match is
+* found then return true. If there is no match, add it to the list
+* and return false;
+*
+* @param[in] i_eepromRecordHeader Header for record we want to add to map
+*
+* @param[in] i_recordHeaderVaddr Virtual address to PNOR copy of header information
+*
+* @param[in] i_instance Node ID that this eeprom is on
+*
+* @return TRUE if entry is already in map FALSE if this is a new entry
+*
+*/
+bool addEepromToCachedList(const eepromRecordHeader & i_eepromRecordHeader,
+ const uint64_t i_recordHeaderVaddr,
+ const uint8_t i_instance);
+
+/**
+*
+* @brief Perform a lookup on the global map g_cachedEeproms to get a
+* virtual address for a given EEPROM cache entry
+*
+* @param[in] i_eepromRecordHeader Header for record we want to add to lookup address for
+*
+* @param[in] i_isntance Node ID that this eeprom is on
+*
+* @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 lookupEepromCacheAddr(const eepromRecordHeader& i_eepromRecordHeader,
+ const uint8_t i_instance);
+
+/**
+*
+* @brief Walk through g_cachedEeproms map and print information about
+* the cached eeproms found
+*
+* @return void
+*
+*/
+void printCurrentCachedEepromMap(void);
+#endif // __HOSTBOOT_RUNTIME
}
#endif \ No newline at end of file
diff --git a/src/usr/i2c/eepromCache_common.C b/src/usr/i2c/eepromCache_common.C
new file mode 100644
index 000000000..72c982056
--- /dev/null
+++ b/src/usr/i2c/eepromCache_common.C
@@ -0,0 +1,325 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/i2c/eepromCache_common.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 "eepromCache.H"
+#include <errl/errlmanager.H>
+#include <i2c/eepromif.H>
+#include <i2c/eepromddreasoncodes.H>
+#include <errl/errludtarget.H>
+
+#ifdef __HOSTBOOT_RUNTIME
+#include <targeting/attrrp.H>
+#else
+#include <sys/mm.h>
+#endif
+
+extern trace_desc_t* g_trac_eeprom;
+
+//#define TRACSSCOMP(args...) TRACFCOMP(args)
+#define TRACSSCOMP(args...)
+
+namespace EEPROM
+{
+
+errlHndl_t buildEepromRecordHeader(TARGETING::Target * i_target,
+ eeprom_addr_t & io_eepromInfo,
+ eepromRecordHeader & o_eepromRecordHeader)
+{
+
+ TARGETING::Target * l_muxTarget = nullptr;
+ TARGETING::Target * l_i2cMasterTarget = nullptr;
+ TARGETING::TargetService& l_targetService = TARGETING::targetService();
+ errlHndl_t l_errl = nullptr;
+
+ do{
+
+ l_errl = eepromReadAttributes(i_target, io_eepromInfo);
+ if(l_errl)
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "buildEepromRecordHeader() error occurred reading eeprom attributes for eepromType %d, target 0x%.08X, returning!!",
+ io_eepromInfo.eepromRole,
+ TARGETING::get_huid(i_target));
+ 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( io_eepromInfo.i2cMuxPath);
+ if(l_muxTarget == nullptr)
+ {
+ 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),
+ io_eepromInfo.eepromRole);
+ /*@
+ * @errortype
+ * @moduleid EEPROM_CACHE_EEPROM
+ * @reasoncode EEPROM_I2C_MUX_PATH_ERROR
+ * @userdata1 HUID of target we want to cache
+ * @userdata2 Type of EEPROM we are caching
+ * @devdesc buildEepromRecordHeader invalid mux target
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_CACHE_EEPROM,
+ EEPROM_I2C_MUX_PATH_ERROR,
+ TARGETING::get_huid(i_target),
+ io_eepromInfo.eepromRole,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ 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( io_eepromInfo.i2cMasterPath );
+ if(l_i2cMasterTarget == nullptr)
+ {
+ 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),
+ io_eepromInfo.eepromRole);
+ /*@
+ * @errortype
+ * @moduleid EEPROM_CACHE_EEPROM
+ * @reasoncode EEPROM_I2C_MASTER_PATH_ERROR
+ * @userdata1 HUID of target we want to cache
+ * @userdata2 Type of EEPROM we are caching
+ * @devdesc buildEepromRecordHeader invalid master target
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_CACHE_EEPROM,
+ EEPROM_I2C_MASTER_PATH_ERROR,
+ TARGETING::get_huid(i_target),
+ io_eepromInfo.eepromRole,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ 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;
+}
+
+errlHndl_t eepromPerformOpCache(DeviceFW::OperationType i_opType,
+ TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t& io_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;
+ }
+
+#ifndef __HOSTBOOT_RUNTIME
+ uint64_t l_eepromCacheVaddr = lookupEepromCacheAddr(l_eepromRecordHeader);
+#else
+ uint8_t l_instance = TARGETING::AttrRP::getNodeId(i_target);
+ uint64_t l_eepromCacheVaddr = lookupEepromCacheAddr(l_eepromRecordHeader, l_instance);
+#endif
+
+ // Ensure that a copy of the eeprom exists in our map of cached eeproms
+ if(l_eepromCacheVaddr)
+ {
+ // First check if io_buffer is a nullptr, if so then assume user is
+ // requesting size back in io_bufferlen
+ if(io_buffer == nullptr)
+ {
+ io_buflen = l_eepromRecordHeader.completeRecord.cache_copy_size * KILOBYTE;
+ TRACSSCOMP( g_trac_eeprom, "eepromPerformOpCache() "
+ "io_buffer == nullptr , returning io_buflen as 0x%lx",
+ io_buflen);
+ break;
+ }
+
+ 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, io_buflen, l_eepromCacheVaddr);
+
+ // Make sure that offset + buflen are less than the total size of the eeprom
+ if(i_eepromInfo.offset + io_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(io_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),
+ io_buflen);
+ }
+ else if(i_opType == DeviceFW::WRITE)
+ {
+ memcpy(reinterpret_cast<void *>(l_eepromCacheVaddr + i_eepromInfo.offset),
+ io_buffer,
+ io_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),
+ io_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
+ }
+ 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/eeprom_utils.C b/src/usr/i2c/eeprom_utils.C
index 806a0cf31..8333ebf49 100644
--- a/src/usr/i2c/eeprom_utils.C
+++ b/src/usr/i2c/eeprom_utils.C
@@ -87,6 +87,18 @@ bool eepromPresence ( TARGETING::Target * i_target )
break;
}
+ // If the target has dynamic device address attribute, then use that instead of the
+ // read-only address found in ATTR_EEPROM_XX_INFO attrs. We use the dynamic address
+ // attribute because ATTR_EEPROM_XX_INFO attrs are not writable and its difficult
+ // to override complex attributes.
+ if(i_target->tryGetAttr<TARGETING::ATTR_DYNAMIC_I2C_DEVICE_ADDRESS>(i2cInfo.devAddr))
+ {
+ TRACDCOMP(g_trac_eeprom,
+ "Using DYNAMIC_I2C_DEVICE_ADDRESS %.2x for HUID %.8x",
+ i2cInfo.devAddr,
+ TARGETING::get_huid(i_target));
+ }
+
//Check for the target at the I2C level
l_present = I2C::i2cPresence(i2cMasterTarget,
i2cInfo.port,
@@ -373,7 +385,7 @@ errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
// Printing mux info separately, if combined, nothing is displayed
char* l_muxPath = o_i2cInfo.i2cMuxPath.toString();
- TRACFCOMP(g_trac_eeprom, "eepromReadAttributes(): "
+ TRACUCOMP(g_trac_eeprom, "eepromReadAttributes(): "
"muxSelector=0x%X, muxPath=%s",
o_i2cInfo.i2cMuxBusSelector,
l_muxPath);
diff --git a/src/usr/i2c/eepromdd.C b/src/usr/i2c/eepromdd.C
index 74b6d3692..2243e9b38 100755
--- a/src/usr/i2c/eepromdd.C
+++ b/src/usr/i2c/eepromdd.C
@@ -41,6 +41,11 @@
// va_list
#include "eepromCache.H"
#include "eepromdd_hardware.H"
+#include <i2c/eepromddreasoncodes.H>
+#ifdef __HOSTBOOT_RUNTIME
+// Need to be able to convert HB target id's to runtime target ids
+#include <targeting/attrrp.H>
+#endif
extern trace_desc_t* g_trac_eeprom;
@@ -87,19 +92,59 @@ errlHndl_t resolveSource(TARGETING::Target * i_target,
err = buildEepromRecordHeader(i_target,
io_i2cInfo,
l_eepromRecordHeader);
+#ifndef __HOSTBOOT_RUNTIME
// if lookupEepromAddr returns non-zero address
// then we know it exists in cache somewhere
- if(lookupEepromAddr(l_eepromRecordHeader))
+ if(lookupEepromCacheAddr(l_eepromRecordHeader))
{
- TRACFCOMP(g_trac_eeprom,"Eeprom found in cache, looking at eecache");
+ TRACDCOMP(g_trac_eeprom,"Eeprom found in cache, looking at eecache");
o_source = EEPROM::CACHE;
}
else
{
- TRACFCOMP(g_trac_eeprom,"Eeprom not found in cache, looking at hardware");
+ TRACDCOMP(g_trac_eeprom,"Eeprom not found in cache, looking at hardware");
o_source = EEPROM::HARDWARE;
}
-
+#else
+ uint8_t l_instance = TARGETING::AttrRP::getNodeId(i_target);
+ // if lookupEepromAddr returns non-zero address
+ // then we know it exists in cache somewhere
+ if(lookupEepromCacheAddr(l_eepromRecordHeader, l_instance))
+ {
+ TRACDCOMP(g_trac_eeprom,"Eeprom found in cache, looking at eecache");
+ o_source = EEPROM::CACHE;
+ }
+ else
+ {
+ /*@
+ * @errortype
+ * @moduleid EEPROM_RESOLVE_SOURCE
+ * @reasoncode EEPROM_CACHE_NOT_FOUND_IN_MAP
+ * @userdata1[0:7] i2c_master_huid
+ * @userdata1[8:9] port on i2c master eeprom slave is on
+ * @userdata1[10:11] engine on i2c master eeprom slave is on
+ * @userdata1[12:13] devAddr of eeprom slave
+ * @userdata1[14:15] muxSelect of eeprom slave (0xFF is not valid)
+ * @userdata2[0:7] size of eeprom
+ * @devdesc resolveSource failed to find cache in map during runtime
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_RESOLVE_SOURCE,
+ EEPROM_CACHE_NOT_FOUND_IN_MAP,
+ 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))),
+ l_eepromRecordHeader.completeRecord.cache_copy_size,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ }
+#endif
return err;
}
@@ -178,29 +223,35 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
if(l_source == EEPROM::CACHE )
{
// Read the copy of the EEPROM data we have cached in PNOR
- err = eepromPerformOpCache(i_opType, i_target, io_buffer, io_buflen, i2cInfo);
+ err = eepromPerformOpCache(i_opType, i_target,
+ io_buffer, io_buflen, i2cInfo);
if(err)
{
break;
}
-
- // If the operation is a write we also need to "write through" to HW after
- // we write cache
+ // TODO RTC:212469 Complete Work needed for Axone i2c runtime support
+ #ifndef __HOSTBOOT_RUNTIME
if(i_opType == DeviceFW::WRITE)
{
- err = eepromPerformOpHW(i_opType, i_target, io_buffer, io_buflen, i2cInfo);
+ // If the operation is a write we also need to
+ // "write through" to HW after we write cache
+ err = eepromPerformOpHW(i_opType, i_target,
+ io_buffer, io_buflen, i2cInfo);
}
+ #endif
}
else if(l_source == EEPROM::HARDWARE)
{
// Read from the actual physical EEPROM device
- err = eepromPerformOpHW(i_opType, i_target, io_buffer, io_buflen, i2cInfo);
+ err = eepromPerformOpHW(i_opType, i_target, io_buffer,
+ io_buflen, i2cInfo);
}
#else
// Read from the actual physical EEPROM device
- err = eepromPerformOpHW(i_opType, i_target, io_buffer, io_buflen, i2cInfo);
+ err = eepromPerformOpHW(i_opType, i_target, io_buffer,
+ io_buflen, i2cInfo);
#endif // CONFIG_SUPPORT_EEPROM_CACHING
diff --git a/src/usr/i2c/eepromdd_hardware.C b/src/usr/i2c/eepromdd_hardware.C
index 351ca549a..b48c3889e 100644
--- a/src/usr/i2c/eepromdd_hardware.C
+++ b/src/usr/i2c/eepromdd_hardware.C
@@ -109,7 +109,7 @@ errlHndl_t eepromPerformOpHW(DeviceFW::OperationType i_opType,
( io_i2cInfo.devSize_KB * KILOBYTE ) )
{
TRACFCOMP( g_trac_eeprom,
- ERR_MRK"eepromPerformOp(): Device Overflow! "
+ ERR_MRK"eepromPerformOpHW(): 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,
@@ -155,19 +155,19 @@ errlHndl_t eepromPerformOpHW(DeviceFW::OperationType i_opType,
l_currentOpLen = l_snglChipSize - io_i2cInfo.offset;
}
- TRACFCOMP( g_trac_eeprom,
- "eepromPerformOp(): i_opType=%d "
+ TRACDCOMP( g_trac_eeprom,
+ "eepromPerformOpHW(): 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)
+ 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",
+ TRACDCOMP (g_trac_eeprom,
+ "eepromPerformOpHW(): 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(): "
+ TRACDCOMP(g_trac_eeprom, "eepromPerformOpHW(): "
"muxSelector=0x%X, muxPath=%s",
io_i2cInfo.i2cMuxBusSelector,
l_muxPath);
@@ -207,7 +207,7 @@ errlHndl_t eepromPerformOpHW(DeviceFW::OperationType i_opType,
else
{
TRACFCOMP( g_trac_eeprom,
- ERR_MRK"eepromPerformOp(): "
+ ERR_MRK"eepromPerformOpHW(): "
"Invalid EEPROM Operation!");
/*@
diff --git a/src/usr/i2c/fapi_i2c_dd.C b/src/usr/i2c/fapi_i2c_dd.C
index bf1771865..35a838998 100644
--- a/src/usr/i2c/fapi_i2c_dd.C
+++ b/src/usr/i2c/fapi_i2c_dd.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2018 */
+/* Contributors Listed Below - COPYRIGHT 2018,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -41,6 +41,8 @@
#include <devicefw/driverif.H>
#include <i2c/i2creasoncodes.H>
#include "fapi_i2c_dd.H"
+#include <time.h>
+#include <stdio.h>
extern trace_desc_t* g_trac_i2c;
@@ -69,6 +71,11 @@ DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
TARGETING::TYPE_OCMB_CHIP,
fapiI2cPerformOp );
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::FAPI_I2C,
+ TARGETING::TYPE_PMIC,
+ fapiI2cPerformOp );
+
errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType,
TARGETING::Target * i_target,
void * io_buffer,
@@ -78,6 +85,7 @@ errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType,
{
errlHndl_t l_err = nullptr;
errlHndl_t l_err_retryable = nullptr;
+ bool l_non_retryable_err_hit = false;
const uint8_t FAPI_I2C_MAX_RETRIES = 2;
TARGETING::ATTR_FAPI_I2C_CONTROL_INFO_type l_i2cInfo;
@@ -89,6 +97,10 @@ errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType,
l_cfgData = va_arg( i_args, uint8_t* );
}
+ timespec_t l_startTime;
+ timespec_t l_endTime;
+ clock_gettime(CLOCK_MONOTONIC, &l_startTime);
+
TRACUCOMP(g_trac_i2c, ENTER_MRK"fapiI2cPerformOp(): "
"%s operation on target %.8X",
(i_opType==DeviceFW::READ)?"READ":"WRITE",
@@ -103,6 +115,18 @@ errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType,
break;
}
+ // If the target has dynamic device address attribute, then use that instead of the
+ // read-only address found in ATTR_FAPI_I2C_CONTROL_INFO. We use the dynamic address
+ // attribute because ATTR_FAPI_I2C_CONTROL_INFO is not writable and its difficult
+ // to override complex attributes.
+ if(i_target->tryGetAttr<TARGETING::ATTR_DYNAMIC_I2C_DEVICE_ADDRESS>(l_i2cInfo.devAddr))
+ {
+ TRACDCOMP(g_trac_i2c,
+ "Using DYNAMIC_I2C_DEVICE_ADDRESS %.2x for HUID %.8x",
+ l_i2cInfo.devAddr,
+ TARGETING::get_huid(i_target));
+ }
+
// grab target pointer to master
TARGETING::TargetService& ts = TARGETING::targetService();
TARGETING::Target * i2cm = ts.toTarget(l_i2cInfo.i2cMasterPath);
@@ -136,8 +160,6 @@ errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType,
TARGETING::get_huid(i_target),
0,
true /*Add HB SW Callout*/ );
-
- l_err->collectTrace( I2C_COMP_NAME );
break;
}
@@ -164,8 +186,6 @@ errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType,
i_opType,
TARGETING::get_huid(i_target),
true /*Add HB SW Callout*/ );
-
- l_err->collectTrace( I2C_COMP_NAME );
break;
}
@@ -204,8 +224,7 @@ errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType,
"Error: rc=0x%X, tgt=0x%X, No Retry (retry=%d)",
l_err->reasonCode(),
TARGETING::get_huid(i_target), retry);
- l_err->collectTrace(I2C_COMP_NAME);
-
+ l_non_retryable_err_hit = true;
// break from retry loop
break;
}
@@ -267,35 +286,54 @@ errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType,
} // end of retryable error loop
+ clock_gettime(CLOCK_MONOTONIC, &l_endTime);
+ char l_time_str[128];
+ snprintf(l_time_str, sizeof(l_time_str),
+ "Start Time: %lu sec %lu ns End Time: %lu sec %lu ns",
+ l_startTime.tv_sec, l_startTime.tv_nsec,
+ l_endTime.tv_sec, l_endTime.tv_nsec);
+
// Handle saved retryable error, if any
if (l_err_retryable)
{
- if (l_err)
+ // This is the case where we had 1 or more retryable errors and
+ // eventually hit a non retryable error.
+ if (l_err && l_non_retryable_err_hit)
{
// commit original retryable error with new err PLID
l_err_retryable->plid(l_err->plid());
TRACFCOMP(g_trac_i2c, "fapiI2cPerformOp(): Committing saved "
"retryable error eid=0x%X with plid of returned err 0x%X",
l_err_retryable->eid(), l_err_retryable->plid());
-
+ ERRORLOG::ErrlUserDetailsString(l_time_str)
+ .addToLog(l_err_retryable);
ERRORLOG::ErrlUserDetailsTarget(i_target)
.addToLog(l_err_retryable);
l_err_retryable->collectTrace(I2C_COMP_NAME);
+ l_err_retryable->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL);
errlCommit(l_err_retryable, I2C_COMP_ID);
}
else
{
- // Since we eventually succeeded,
- // delete original retryable error
- TRACUCOMP(g_trac_i2c, "fapiI2cPerformOp(): Op successful, "
- "deleting saved retryable err eid=0x%X, plid=0x%X",
+ // In this case we have either hit the max retryable errors and
+ // failed, or hit one or more retryable errors and eventually
+ // passed. Either way we do not need this l_err_retryable anymore.
+ TRACUCOMP(g_trac_i2c, "fapiI2cPerformOp(): Op successful, or we hit max Retries and"
+ " the caller is polling on this i2c op. Deleting saved retryable err eid=0x%X,"
+ " plid=0x%X.",
l_err_retryable->eid(), l_err_retryable->plid());
-
delete l_err_retryable;
l_err_retryable = nullptr;
}
}
+ if(l_err)
+ {
+ ERRORLOG::ErrlUserDetailsString(l_time_str)
+ .addToLog(l_err);
+ l_err->collectTrace(I2C_COMP_NAME);
+ }
+
} while (0);
return l_err;
@@ -376,10 +414,10 @@ errlHndl_t i2cWrite( TARGETING::Target * i_target,
i_buffer,
io_buffer_size,
DEVICE_I2C_ADDRESS(i_i2cInfo->port,
- i_i2cInfo->engine,
- i_i2cInfo->devAddr,
- i_i2cInfo->i2cMuxBusSelector,
- &(i_i2cInfo->i2cMuxPath) ) );
+ i_i2cInfo->engine,
+ i_i2cInfo->devAddr,
+ i_i2cInfo->i2cMuxBusSelector,
+ &(i_i2cInfo->i2cMuxPath) ) );
if( l_err )
{
diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C
index 63b579202..2439f1eff 100755
--- a/src/usr/i2c/i2c.C
+++ b/src/usr/i2c/i2c.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2019 */
+/* Contributors Listed Below - COPYRIGHT 2011,2020 */
/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
@@ -94,6 +94,7 @@ TRAC_INIT( & g_trac_i2cr, "I2CR", KILOBYTE );
#define MAX_NACK_RETRIES 3
#define PAGE_OPERATION 0xffffffff // Special value use to determine type of op
#define P9_ENGINE_SCOM_OFFSET 0x1000
+constexpr uint64_t FSI_BUS_SPEED_MHZ = 133; //FSI runs at 133MHz
// Derived from ATTR_I2C_BUS_SPEED_ARRAY[engine][port] attribute
const TARGETING::ATTR_I2C_BUS_SPEED_ARRAY_type g_var = {{NULL}};
@@ -447,14 +448,16 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
// Else this is not a page operation, call the normal common function
else
{
- if( (subop==DeviceFW::I2C_SMBUS_BLOCK)
- || (subop==DeviceFW::I2C_SMBUS_BYTE)
- || (subop==DeviceFW::I2C_SMBUS_WORD))
+ if( (subop == DeviceFW::I2C_SMBUS_BLOCK)
+ || (subop == DeviceFW::I2C_SMBUS_BYTE)
+ || (subop == DeviceFW::I2C_SMBUS_WORD)
+ || (subop == DeviceFW::I2C_SMBUS_WORD_NO_PEC)
+ || (subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT) )
{
args.smbus.commandCode =
static_cast<decltype(args.smbus.commandCode)>(
va_arg(i_args,uint64_t));
- args.smbus.usePec = true; // All implementations use PEC
+ args.smbus.usePec = true; // Most implementations use PEC
args.i2cMuxBusSelector = va_arg(i_args,uint64_t);
args.i2cMuxPath = reinterpret_cast<const TARGETING::EntityPath*>(
va_arg(i_args, uint64_t));
@@ -477,11 +480,23 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
if ( args.offset_length != 0 )
{
args.offset_buffer = temp;
-
}
}
- args.subop=subop;
+ if (subop == DeviceFW::I2C_SMBUS_WORD_NO_PEC)
+ {
+ args.smbus.usePec = false;
+ args.subop = DeviceFW::I2C_SMBUS_WORD;
+ }
+ else if (subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT)
+ {
+ args.smbus.usePec = false;
+ args.subop=subop;
+ }
+ else
+ {
+ args.subop=subop;
+ }
err = i2cCommonOp( i_opType,
i_target,
@@ -1284,11 +1299,22 @@ errlHndl_t i2cAccessMux( TARGETING::Target* i_masterTarget,
if (! (l_i2cMuxTarget->tryGetAttr<TARGETING::ATTR_FAPI_I2C_CONTROL_INFO>(l_muxData)) )
{
TRACFCOMP(g_trac_i2c,
- "i2cAccessMux(): get attributes failed");
+ "i2cAccessMux(): getting ATTR_FAPI_I2C_CONTROL_INFO failed");
break;
}
- uint8_t l_muxSelector = i_i2cMuxBusSelector;
+ TARGETING::ATTR_MODEL_type l_muxModel;
+ if (! (l_i2cMuxTarget->tryGetAttr<TARGETING::ATTR_MODEL>(l_muxModel)) )
+ {
+ TRACFCOMP(g_trac_i2c,
+ "i2cAccessMux(): getting ATTR_MODEL failed");
+ break;
+ }
+
+ assert(l_muxModel == TARGETING::MODEL_PCA9847, "Invalid model of mux detected");
+ const uint8_t PCA9847_ENABLE_BIT = 8;
+
+ uint8_t l_muxSelector = i_i2cMuxBusSelector | PCA9847_ENABLE_BIT;
uint8_t *l_ptrMuxSelector = &l_muxSelector;
size_t l_muxSelectorSize = sizeof(l_muxSelector);
@@ -1430,7 +1456,8 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
/*******************************************************/
/* Perform the I2C Operation */
/*******************************************************/
-
+ TRACUCOMP( g_trac_i2c, INFO_MRK "i2cCommonOp() -- opType: %d, subOp: %d",
+ static_cast<uint64_t>(i_opType), i_args.subop);
/***********************************************/
/* I2C SMBUS Send Byte */
/***********************************************/
@@ -1598,14 +1625,16 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
/***********************************************/
/* I2C SMBUS Block Write */
/***********************************************/
- else if( (i_opType == DeviceFW::WRITE )
- && (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK))
+ else if( (i_opType == DeviceFW::WRITE ) &&
+ ((i_args.subop == DeviceFW::I2C_SMBUS_BLOCK) ||
+ (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT)) )
{
TRACUCOMP(g_trac_i2c, INFO_MRK
- "I2C SMBUS Block Write: Command code = 0x%02X, "
- "Use PEC = %d. io_buflen = %lu",
- i_args.smbus.commandCode,
- i_args.smbus.usePec, io_buflen);
+ "I2C SMBUS Block Write: Command code = 0x%02X, SubCmd = 0x%02X "
+ "Use PEC = %d. io_buflen = %lu, io_buffer byte0: 0x%02X",
+ i_args.smbus.commandCode, i_args.subop,
+ i_args.smbus.usePec, io_buflen,
+ *reinterpret_cast<uint8_t*>(io_buffer));
// If requested length is for < 1 byte or > 255 bytes for a block
// write transaction, throw an error.
@@ -1649,12 +1678,29 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
io_buflen,
io_buffer,
i_args.smbus.usePec);
+ void * writeStart = &blockWrite.commandCode;
+
+ // byteCount might be altered into commandCode, so store its value
+ size_t dataByteCount = blockWrite.byteCount;
+ if (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT)
+ {
+ // Moving commandCode down a byte so it is followed
+ // immediately by dataBytes[] instead of byteCount
+ // (this removes byteCount from the block write)
+ writeStart = &blockWrite.byteCount;
+ blockWrite.byteCount = blockWrite.commandCode;
+ blockWrite.messageSize -= sizeof(blockWrite.commandCode);
+ TRACUCOMP(g_trac_i2c, INFO_MRK
+ "I2C SMBUS Block Write no-byte-count: removing byteCount,"
+ " msgSize = %d", blockWrite.messageSize);
+ }
+
do {
size_t writeSize = blockWrite.messageSize;
const auto writeSizeExp = writeSize;
err = i2cWrite(i_target,
- &blockWrite.commandCode,
+ writeStart,
writeSize,
i_args);
if(err)
@@ -1666,7 +1712,8 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
"Write size mismatch; expected %d but got %d",
writeSizeExp,writeSize);
- io_buflen = blockWrite.byteCount;
+
+ io_buflen = dataByteCount;
} while(0);
@@ -4308,13 +4355,23 @@ errlHndl_t i2cSetBusVariables ( TARGETING::Target * i_target,
if ( io_args.switches.useFsiI2C == 1 )
{
- // @todo RTC 117560 - verify correct frequency
- local_bus_MHZ = g_I2C_NEST_FREQ_MHZ;
+ // For FSI I2C we should use the FSI clock
+ local_bus_MHZ = FSI_BUS_SPEED_MHZ;
}
else
{
- // For Host I2C use Nest Frequency
- local_bus_MHZ = g_I2C_NEST_FREQ_MHZ;
+ // For Host I2C use Nest Frequency as base
+
+ // PIB_CLK = NEST_FREQ / 4
+ uint64_t pib_clk = g_I2C_NEST_FREQ_MHZ / 4;
+
+#ifdef CONFIG_AXONE
+ // Axone has a by-2 internal divider
+ local_bus_MHZ = pib_clk / 2;
+#else
+ // Nimbus/Cumulus have a by-4 internal divider
+ local_bus_MHZ = pib_clk / 4;
+#endif
}
io_args.bit_rate_divisor = i2cGetBitRateDivisor(io_args.bus_speed,
@@ -5148,8 +5205,13 @@ void getMasterInfo( const TARGETING::Target* i_chip,
info.engine = engine;
info.freq = i2cGetNestFreq()*FREQ_CONVERSION::HZ_PER_MHZ;
// PIB_CLK = NEST_FREQ /4
- // Local Bus = PIB_CLK / 4
+#ifdef CONFIG_AXONE
+ // Local Bus = PIB_CLK / 2 [Axone]
+ info.freq = info.freq/8; //convert nest to local bus
+#else
+ // Local Bus = PIB_CLK / 4 [Nimbus/Cumulus]
info.freq = info.freq/16; //convert nest to local bus
+#endif
TRACFCOMP(g_trac_i2c,"getMasterInfo(%.8X): pushing back engine=%d, scomAddr=0x%X",TARGETING::get_huid(i_chip), engine, info.scomAddr);
@@ -5447,6 +5509,7 @@ void getDeviceInfo( TARGETING::Target* i_i2cMaster,
// Lookup i2c info for the TPM
l_err = TPMDD::tpmReadAttributes(pTpm,
tpmInfo, locality);
+
if( NULL != l_err )
{
// Unable to get info, so we skip
@@ -5474,11 +5537,34 @@ void getDeviceInfo( TARGETING::Target* i_i2cMaster,
l_currentDI.slavePort = 0xFF;
l_currentDI.busFreqKhz = (tpmInfo.busFreq)
/ FREQ_CONVERSION::HZ_PER_KHZ;
- l_currentDI.deviceType =
- TARGETING::HDAT_I2C_DEVICE_TYPE_NUVOTON_TPM;
l_currentDI.devicePurpose =
TARGETING::HDAT_I2C_DEVICE_PURPOSE_TPM;
- strcpy(l_currentDI.deviceLabel,"?nuvoton,npct601,tpm,host");
+
+ // Read TPM Model attribute to determine some values
+ if (tpmInfo.model == TPMDD::TPM_MODEL_65x)
+ {
+ strcpy(l_currentDI.deviceLabel,"?nuvoton,npct601,tpm,host");
+ l_currentDI.deviceType =
+ TARGETING::HDAT_I2C_DEVICE_TYPE_NUVOTON_TPM;
+ }
+ else if (tpmInfo.model == TPMDD::TPM_MODEL_75x)
+ {
+ strcpy(l_currentDI.deviceLabel,"?tcg,tpm_i2c_ptp,tpm,host");
+ l_currentDI.deviceType =
+ TARGETING::HDAT_I2C_DEVICE_TYPE_TCG_I2C_TPM;
+ }
+ else
+ {
+ // Should never get here as tpmReadAttributes will fail if
+ // unknown TPM Model, but just in case do this:
+ strcpy(l_currentDI.deviceLabel,
+ "?unknwon,unknown,tpm,host");
+ }
+
+ TRACUCOMP(g_trac_i2c,"TPM 0x%X is Model %d using label %s",
+ TARGETING::get_huid(pTpm),
+ tpmInfo.model,
+ l_currentDI.deviceLabel);
o_deviceInfo.push_back(l_currentDI);
} //end of tpm iter
diff --git a/src/usr/i2c/i2c.H b/src/usr/i2c/i2c.H
index eca944479..6f230ac58 100755
--- a/src/usr/i2c/i2c.H
+++ b/src/usr/i2c/i2c.H
@@ -112,10 +112,10 @@ static uint64_t g_I2C_NEST_FREQ_MHZ = i2cGetNestFreq();
ALWAYS_INLINE inline uint16_t i2cGetBitRateDivisor(uint64_t i_bus_speed_khz,
uint64_t i_local_bus_MHZ)
{
- // BRD = ( ( ( LocalBus_MHZ / 16 ) / i_bus_speed_khz ) - 1 ) / 4
+ // BRD = ( ( LocalBus_MHZ) / i_bus_speed_khz ) - 1 ) / 4
// Use tmp variable to convert everything to KHZ safely
- uint64_t tmp = ( i_local_bus_MHZ / 16 ) * 1000;
+ uint64_t tmp = i_local_bus_MHZ * 1000;
return ( ( ( tmp / i_bus_speed_khz ) - 1 ) / 4 );
}
diff --git a/src/usr/i2c/i2c.mk b/src/usr/i2c/i2c.mk
index 6d4ef8935..0300d2c46 100644
--- a/src/usr/i2c/i2c.mk
+++ b/src/usr/i2c/i2c.mk
@@ -5,7 +5,7 @@
#
# OpenPOWER HostBoot Project
#
-# Contributors Listed Below - COPYRIGHT 2015
+# Contributors Listed Below - COPYRIGHT 2015,2019
# [+] International Business Machines Corp.
#
#
@@ -27,4 +27,4 @@ OBJS += eepromdd.o
OBJS += eepromdd_hardware.o
OBJS += eeprom_utils.o
OBJS += errlud_i2c.o
-OBJS += $(if $(CONFIG_SUPPORT_EEPROM_CACHING),eepromCache.o)
+OBJS += $(if $(CONFIG_SUPPORT_EEPROM_CACHING),eepromCache_common.o)
diff --git a/src/usr/i2c/i2cTargetPres.C b/src/usr/i2c/i2cTargetPres.C
index c3809f099..c7c9421a3 100644
--- a/src/usr/i2c/i2cTargetPres.C
+++ b/src/usr/i2c/i2cTargetPres.C
@@ -32,7 +32,7 @@
#include <initservice/initserviceif.H>
#include <errl/errlmanager.H>
#include "i2c_common.H"
-
+#include <fapiwrap/fapiWrapif.H>
extern trace_desc_t* g_trac_i2c;
@@ -182,6 +182,18 @@ errlHndl_t genericI2CTargetPresenceDetect(TARGETING::Target* i_target,
//* If we make it through all of the checks then we have verified master is present *
//***********************************************************************************
+ // If the target has dynamic device address attribute, then use that instead of the
+ // read-only address found in ATTR_FAPI_I2C_CONTROL_INFO. We use the dynamic address
+ // attribute because ATTR_FAPI_I2C_CONTROL_INFO is not writable and its difficult
+ // to override complex attributes.
+ if(i_target->tryGetAttr<TARGETING::ATTR_DYNAMIC_I2C_DEVICE_ADDRESS>(l_i2cInfo.devAddr))
+ {
+ TRACDCOMP(g_trac_i2c,
+ "Using DYNAMIC_I2C_DEVICE_ADDRESS %.2x for HUID %.8x",
+ l_i2cInfo.devAddr,
+ TARGETING::get_huid(i_target));
+ }
+
//Check for the target at the I2C level
l_target_present = I2C::i2cPresence(l_i2cMasterTarget,
l_i2cInfo.port,
@@ -223,10 +235,6 @@ errlHndl_t ocmbI2CPresencePerformOp(DeviceFW::OperationType i_opType,
{
errlHndl_t l_invalidateErrl = nullptr;
- // @TODO RTC 208696: Gemini vs Explorer Presence Detection via SPD
- // This function will be updated to differentiate between Explorer and
- // Gemini OCMB chips. For now, presense of an OCMB chip is inferred by
- // the presense of the eeprom.
bool l_ocmbPresent = EEPROM::eepromPresence(i_target);
memcpy(io_buffer, &l_ocmbPresent, sizeof(l_ocmbPresent));
@@ -236,10 +244,97 @@ errlHndl_t ocmbI2CPresencePerformOp(DeviceFW::OperationType i_opType,
}
/**
- * @brief Performs a presence detect operation on a Target that has the
+ * @brief Performs a presence detect operation on a PMIC Target
+ *
+ * @param[in] i_opType Operation type, see DeviceFW::OperationType
+ * in driverif.H
+ * @param[in] i_target Presence detect target
+ * @param[in/out] io_buffer Read: Pointer to output data storage
+ * Write: Pointer to input data storage
+ * @param[in/out] io_buflen Input: size of io_buffer (in bytes, always 1)
+ * Output: Success = 1, Failure = 0
+ * @param[in] i_accessType DeviceFW::AccessType enum (userif.H)
+ * @param[in] i_args This is an argument list for DD framework.
+ * In this function, there are no arguments.
+ * @return errlHndl_t
+ */
+errlHndl_t pmicI2CPresencePerformOp(DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args)
+{
+
+ errlHndl_t l_errl = nullptr;
+ bool l_pmicPresent = 0;
+ uint8_t l_devAddr;
+ TARGETING::Target* l_parentOcmb = TARGETING::getImmediateParentByAffinity(i_target);
+ auto l_parentHwasState = l_parentOcmb->getAttr<TARGETING::ATTR_HWAS_STATE>();
+
+ do{
+
+ if(! l_parentHwasState.present)
+ {
+ // If the parent chip is not present, then neither is the pmic
+ // so just break out and return not present
+ break;
+ }
+
+ TARGETING::ATTR_REL_POS_type l_relPos = i_target->getAttr<TARGETING::ATTR_REL_POS>();
+
+ // PMICs will have a different device address depending on the vendor.
+ // Prior to doing present detection on a pmic we must first query the
+ // device address from the parent OCMB's SPD
+ l_errl = FAPIWRAP::get_pmic_dev_addr(l_parentOcmb,
+ l_relPos,
+ l_devAddr);
+ if (l_errl)
+ {
+ TRACFCOMP( g_trac_i2c, ERR_MRK"pmicI2CPresencePerformOp() "
+ "Error attempting to read pmic device address on OCMB 0x%.08X",
+ TARGETING::get_huid(l_parentOcmb));
+ break;
+ }
+
+ assert(l_devAddr != 0,
+ "Found devAddr for PMIC 0x%.08x to be 0, this cannot be. Check SPD and REL_POS on target",
+ TARGETING::get_huid(i_target));
+
+ if(l_devAddr == FAPIWRAP::NO_PMIC_DEV_ADDR)
+ {
+ // There is no pmic device address for this rel position on this ocmb so
+ // break and return not present.
+ break;
+ }
+
+ i_target->setAttr<TARGETING::ATTR_DYNAMIC_I2C_DEVICE_ADDRESS>(l_devAddr);
+
+ l_errl = genericI2CTargetPresenceDetect(i_target,
+ io_buflen,
+ l_pmicPresent);
+
+ if (l_errl)
+ {
+ TRACFCOMP( g_trac_i2c, ERR_MRK"pmicI2CPresencePerformOp() "
+ "Error detecting target 0x%.08X, io_buffer will not be set",
+ TARGETING::get_huid(i_target));
+ break;
+ }
+
+ // Copy variable describing if target is present or not to i/o buffer param
+ memcpy(io_buffer, &l_pmicPresent, sizeof(l_pmicPresent));
+ io_buflen = sizeof(l_pmicPresent);
+
+ }while(0);
+
+ return l_errl;
+}
+
+/**
+ * @brief Performs a presence detect operation on a Mux Target that has the
* ATTR_FAPI_I2C_CONTROL_INFO and can be detected via that device
*
- * Currently used to detect I2C_MUTEX targets
*
* @param[in] i_opType Operation type, see DeviceFW::OperationType
* in driverif.H
@@ -253,7 +348,7 @@ errlHndl_t ocmbI2CPresencePerformOp(DeviceFW::OperationType i_opType,
* In this function, there are no arguments.
* @return errlHndl_t
*/
-errlHndl_t basicI2CPresencePerformOp(DeviceFW::OperationType i_opType,
+errlHndl_t muxI2CPresencePerformOp(DeviceFW::OperationType i_opType,
TARGETING::Target* i_target,
void* io_buffer,
size_t& io_buflen,
@@ -261,13 +356,13 @@ errlHndl_t basicI2CPresencePerformOp(DeviceFW::OperationType i_opType,
va_list i_args)
{
bool l_muxPresent = 0;
- errlHndl_t l_returnedError = nullptr;
+ errlHndl_t l_errl = nullptr;
- l_returnedError = genericI2CTargetPresenceDetect(i_target,
- io_buflen,
- l_muxPresent);
+ l_errl = genericI2CTargetPresenceDetect(i_target,
+ io_buflen,
+ l_muxPresent);
- if (l_returnedError)
+ if (l_errl)
{
TRACFCOMP( g_trac_i2c, ERR_MRK"basicI2CTargetPresenceDetect() "
"Error detecting target 0x%.08X, io_buffer will not be set",
@@ -280,7 +375,7 @@ errlHndl_t basicI2CPresencePerformOp(DeviceFW::OperationType i_opType,
io_buflen = sizeof(l_muxPresent);
}
- return l_returnedError;
+ return l_errl;
}
// Register the ocmb presence detect function with the device framework
@@ -293,12 +388,12 @@ DEVICE_REGISTER_ROUTE(DeviceFW::READ,
DEVICE_REGISTER_ROUTE( DeviceFW::READ,
DeviceFW::PRESENT,
TARGETING::TYPE_I2C_MUX,
- basicI2CPresencePerformOp );
+ muxI2CPresencePerformOp );
// Register the pmic vrm presence detect function with the device framework
DEVICE_REGISTER_ROUTE( DeviceFW::READ,
DeviceFW::PRESENT,
TARGETING::TYPE_PMIC,
- basicI2CPresencePerformOp );
+ pmicI2CPresencePerformOp );
}
diff --git a/src/usr/i2c/makefile b/src/usr/i2c/makefile
index 535484752..10e55c9de 100644
--- a/src/usr/i2c/makefile
+++ b/src/usr/i2c/makefile
@@ -33,6 +33,7 @@ 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/runtime/makefile b/src/usr/i2c/runtime/makefile
index e6bf9330b..73d3d464b 100644
--- a/src/usr/i2c/runtime/makefile
+++ b/src/usr/i2c/runtime/makefile
@@ -1,11 +1,11 @@
# IBM_PROLOG_BEGIN_TAG
# This is an automatically generated prolog.
#
-# $Source: src/usr/vpd/runtime/makefile $
+# $Source: src/usr/i2c/runtime/makefile $
#
# OpenPOWER HostBoot Project
#
-# Contributors Listed Below - COPYRIGHT 2013,2015
+# Contributors Listed Below - COPYRIGHT 2013,2019
# [+] International Business Machines Corp.
#
#
@@ -32,7 +32,7 @@ include ../i2c.mk
#add unique object modules
OBJS += rt_i2c.o
-
+OBJS += $(if $(CONFIG_SUPPORT_EEPROM_CACHING),rt_eepromCache.o)
VPATH += ..
include $(ROOTPATH)/config.mk
diff --git a/src/usr/i2c/runtime/rt_eepromCache.C b/src/usr/i2c/runtime/rt_eepromCache.C
new file mode 100644
index 000000000..2b775ddb5
--- /dev/null
+++ b/src/usr/i2c/runtime/rt_eepromCache.C
@@ -0,0 +1,285 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/i2c/runtime/rt_eepromCache.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,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 */
+/**
+ * @file rt_eepromCache.C
+ *
+ * @brief Runtime functionality of the eeprom cache driver
+ *
+ */
+
+// ----------------------------------------------
+// Includes
+// ----------------------------------------------
+
+#include <errl/errlentry.H>
+#include <devicefw/driverif.H>
+#include <i2c/eepromddreasoncodes.H>
+#include <runtime/interface.h>
+#include <targeting/runtime/rt_targeting.H>
+#include <targeting/common/utilFilter.H>
+#include <targeting/attrrp.H>
+#include <trace/interface.H>
+#include <util/runtime/util_rt.H>
+#include <sys/internode.h>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+
+#include "../eepromCache.H"
+
+// ----------------------------------------------
+// Trace definitions
+// ----------------------------------------------
+extern trace_desc_t* g_trac_eeprom;
+
+//#define TRACSSCOMP(args...) TRACFCOMP(args)
+#define TRACSSCOMP(args...)
+
+namespace EEPROM
+{
+
+// 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;
+
+uint64_t g_eecachePnorVaddr[MAX_NODES_PER_SYS] = {0,0,0,0,0,0,0,0};
+std::map<eepromRecordHeader, EeepromEntryMetaData_t> g_cachedEeproms[MAX_NODES_PER_SYS];
+
+// ------------------------------------------------------------------
+// rtEecacheInit
+// ------------------------------------------------------------------
+struct rtEecacheInit
+{
+ rtEecacheInit()
+ {
+ errlHndl_t l_errl = nullptr;
+
+ // Add cache status for the node
+ TARGETING::TargetHandleList l_nodeList;
+ getEncResources(l_nodeList,
+ TARGETING::TYPE_NODE,
+ TARGETING::UTIL_FILTER_ALL);
+ // Find all the targets with VPD switches
+ for (auto & l_node : l_nodeList)
+ {
+ uint8_t l_instance = TARGETING::AttrRP::getNodeId(l_node);
+ uint64_t vpd_size = 0;
+ eecacheSectionHeader* l_sectionHeader =
+ reinterpret_cast<eecacheSectionHeader*>(
+ hb_get_rt_rsvd_mem(Util::HBRT_MEM_LABEL_VPD,
+ l_instance, vpd_size));
+
+ g_eecachePnorVaddr[l_instance] = reinterpret_cast<uint64_t>(l_sectionHeader);
+
+ // Check if reserved memory does not exist for this instance
+ if ((NULL == l_sectionHeader) || (0 == vpd_size))
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "rtEecacheInit(): ERROR Could not find VPD section of reserved memory for Node %d, ",
+ l_instance);
+ /*@
+ * @errortype ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_CACHE_INIT_RT
+ * @reasoncode EEPROM_CACHE_NO_VPD_IN_RSV_MEM
+ * @userdata1 Node Id
+ * @userdata2 Unused
+ *
+ * @devdesc Attempted to lookup VPD in reserved memory
+ * and failed
+ * @custdesc A problem occurred during the IPL of the
+ * system.
+ */
+ l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM::EEPROM_CACHE_INIT_RT,
+ EEPROM::EEPROM_CACHE_NO_VPD_IN_RSV_MEM,
+ l_instance,
+ 0,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ errlCommit (l_errl, EEPROM_COMP_ID);
+ break;
+
+ }
+
+ eepromRecordHeader * l_recordHeaderToCopy = nullptr;
+ uint8_t l_eepromCount = 0;
+ for(int8_t i = 0; i < MAX_EEPROMS_VERSION_1; i++)
+ {
+ // Keep track of current record so we can use outside for loop
+ l_recordHeaderToCopy = &l_sectionHeader->recordHeaders[i];
+
+ // If internal_offset is UNSET_INTERNAL_OFFSET_VALUE then we will assume this address not been filled
+ if(l_recordHeaderToCopy->completeRecord.internal_offset != UNSET_INTERNAL_OFFSET_VALUE)
+ {
+ l_eepromCount++;
+ // Will return true if already found an entry in the list
+ if(addEepromToCachedList(*l_recordHeaderToCopy,
+ reinterpret_cast<uint64_t>(l_recordHeaderToCopy),
+ l_instance))
+ {
+
+ TRACFCOMP(g_trac_eeprom,
+ "rtEecacheInit(): ERROR Duplicate cache entries found in VPD reserved memory section");
+ /*@
+ * @errortype ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_CACHE_INIT_RT
+ * @reasoncode EEPROM_DUPLICATE_CACHE_ENTRY
+ * @userdata1[0:31] i2c_master_huid
+ * @userdata1[32:39] port on i2c master eeprom slave is on
+ * @userdata1[40:47] engine on i2c master eeprom slave is on
+ * @userdata1[48:55] devAddr of eeprom slave
+ * @userdata1[56:63] muxSelect of eeprom slave (0xFF is not valid)
+ * @userdata2[0:31] size of eeprom
+ * @userdata2[32:63] Node Id
+ * @devdesc Attempted to lookup VPD in reserved memory
+ * and failed
+ * @custdesc A problem occurred during the IPL of the
+ * system.
+ */
+ l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM::EEPROM_CACHE_INIT_RT,
+ EEPROM::EEPROM_DUPLICATE_CACHE_ENTRY,
+ TWO_UINT32_TO_UINT64(
+ l_recordHeaderToCopy->completeRecord.i2c_master_huid,
+ TWO_UINT16_TO_UINT32(
+ TWO_UINT8_TO_UINT16(
+ l_recordHeaderToCopy->completeRecord.port,
+ l_recordHeaderToCopy->completeRecord.engine),
+ TWO_UINT8_TO_UINT16(
+ l_recordHeaderToCopy->completeRecord.devAddr,
+ l_recordHeaderToCopy->completeRecord.mux_select))),
+ TWO_UINT32_TO_UINT64(l_recordHeaderToCopy->completeRecord.cache_copy_size,
+ TO_UINT32(l_instance)),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ errlCommit (l_errl, EEPROM_COMP_ID);
+ // Something is wrong so we have committed the unrecoverable
+ // but keep processing the eeproms because we want a full picture
+ // of what we understand the eeprom cache contents to be
+ continue;
+ }
+ }
+ }
+
+ TRACFCOMP(g_trac_eeprom, "Found %d cached eeproms in reserved memory for node %d",
+ l_eepromCount, l_instance);
+
+ printCurrentCachedEepromMap();
+
+ }
+ }
+
+};
+rtEecacheInit g_rtEecacheInit;
+
+void printCurrentCachedEepromMap(void)
+{
+ TRACFCOMP( g_trac_eeprom,
+ "printCurrentCachedEepromMap():");
+
+ mutex_lock(&g_eecacheMutex);
+ for(int8_t i = 0; i < MAX_NODES_PER_SYS; i++)
+ {
+ for(std::map<eepromRecordHeader, EeepromEntryMetaData_t>::iterator iter = g_cachedEeproms[i].begin();
+ iter != g_cachedEeproms[i].end();
+ ++iter)
+ {
+ TRACSSCOMP( g_trac_eeprom,
+ "printTableOfContents(): I2CM Huid: 0x%.08X, Port: 0x%.02X,"
+ " Engine: 0x%.02X, Dev Addr: 0x%.02X,"
+ " Mux Select: 0x%.02X, Size: 0x%.08X",
+ iter->first.completeRecord.i2c_master_huid,
+ iter->first.completeRecord.port,
+ iter->first.completeRecord.engine,
+ iter->first.completeRecord.devAddr,
+ iter->first.completeRecord.mux_select,
+ iter->first.completeRecord.cache_copy_size);
+
+ TRACSSCOMP( g_trac_eeprom,
+ " "
+ "Internal Offset: 0x%.08X, Cache Valid: 0x%.02X",
+ iter->first.completeRecord.internal_offset,
+ iter->first.completeRecord.cached_copy_valid);
+ }
+ }
+ mutex_unlock(&g_eecacheMutex);
+
+}
+
+uint64_t lookupEepromCacheAddr(const eepromRecordHeader& i_eepromRecordHeader,
+ const uint8_t i_instance)
+{
+ uint64_t l_vaddr = 0;
+ std::map<eepromRecordHeader, EeepromEntryMetaData_t>::iterator l_it;
+
+ // Wrap lookup in mutex because reads are not thread safe
+ mutex_lock(&g_eecacheMutex);
+ l_it = g_cachedEeproms[i_instance].find(i_eepromRecordHeader);
+
+ if(l_it != g_cachedEeproms[i_instance].end())
+ {
+ l_vaddr = l_it->second.cache_entry_address;
+ }
+ mutex_unlock(&g_eecacheMutex);
+ return l_vaddr;
+}
+
+bool addEepromToCachedList(const eepromRecordHeader & i_eepromRecordHeader,
+ const uint64_t i_recordHeaderVaddr,
+ const uint8_t i_instance)
+{
+ bool l_matchFound = true;
+
+ // Map accesses are not thread safe, make sure this is always wrapped in mutex
+ mutex_lock(&g_eecacheMutex);
+
+ if(g_cachedEeproms[i_instance].find(i_eepromRecordHeader) ==
+ g_cachedEeproms[i_instance].end())
+ {
+ g_cachedEeproms[i_instance][i_eepromRecordHeader].cache_entry_address =
+ g_eecachePnorVaddr[i_instance] + i_eepromRecordHeader.completeRecord.internal_offset;
+
+ g_cachedEeproms[i_instance][i_eepromRecordHeader].header_entry_address =
+ i_recordHeaderVaddr;
+
+ 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;
+}
+
+} // end namespace EEPROM
diff --git a/src/usr/i2c/runtime/rt_i2c.C b/src/usr/i2c/runtime/rt_i2c.C
index 16f62c76e..d3f5537c6 100755
--- a/src/usr/i2c/runtime/rt_i2c.C
+++ b/src/usr/i2c/runtime/rt_i2c.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2019 */
+/* Contributors Listed Below - COPYRIGHT 2015,2020 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -41,7 +41,7 @@
#include <devicefw/driverif.H>
#include <i2c/i2creasoncodes.H>
#include <runtime/interface.h>
-#include <runtime/rt_targeting.H>
+#include <targeting/runtime/rt_targeting.H>
#include "../errlud_i2c.H"
// ----------------------------------------------
@@ -146,10 +146,10 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
int rc = 0;
bool l_host_if_enabled = true;
- RT_TARG::rtChipId_t proc_id = 0;
+ TARGETING::rtChipId_t proc_id = 0;
// Convert target to proc id
- err = RT_TARG::getRtTarget( i_target,
+ err = TARGETING::getRtTarget( i_target,
proc_id);
if(err)
{
diff --git a/src/usr/i2c/test/eecachetest.H b/src/usr/i2c/test/eecachetest.H
new file mode 100644
index 000000000..cc5233bf6
--- /dev/null
+++ b/src/usr/i2c/test/eecachetest.H
@@ -0,0 +1,121 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/i2c/test/eecachetest.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2011,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 __EECACHETEST_H
+#define __EECACHETEST_H
+
+/**
+ * @file eepromtest.H
+ *
+ * @brief Test cases for the eeprom cache code
+ */
+
+#include <cxxtest/TestSuite.H>
+#include "../eepromCache.H"
+
+extern trace_desc_t* g_trac_eeprom;
+
+using namespace TARGETING;
+using namespace EEPROM;
+
+class EECACHETest: public CxxTest::TestSuite
+{
+ public:
+
+ /**
+ * @brief Verify we can mark a cache as invalid then mark it valid again
+ */
+ void test_invalidateCache( void )
+ {
+ uint8_t l_numTests = 0;
+ uint8_t l_numFails = 0;
+
+ TRACFCOMP( g_trac_eeprom, ENTER_MRK"test_invalidateCache" );
+
+ do{
+ // Uncomment to verify manually
+ //printTableOfContents();
+
+ // Get a processor Target
+ TARGETING::TargetService& tS = TARGETING::targetService();
+ TARGETING::Target* testTarget = NULL;
+ tS.masterProcChipTargetHandle( testTarget );
+ assert(testTarget != NULL);
+
+ // Create dummy eeprom info w/ VPD_PRIMARY set
+ const EEPROM_ROLE l_eepromRole = EEPROM::VPD_PRIMARY;
+
+ eeprom_addr_t l_primaryVpdEeprom;
+ l_primaryVpdEeprom.eepromRole = l_eepromRole;
+
+ eepromRecordHeader l_eepromRecordHeader_forLookup;
+ eepromRecordHeader * l_eepromRecordHeader_realPnor;
+
+ buildEepromRecordHeader( testTarget,
+ l_primaryVpdEeprom,
+ l_eepromRecordHeader_forLookup);
+
+ l_eepromRecordHeader_realPnor = reinterpret_cast<eepromRecordHeader *>(lookupEepromHeaderAddr(l_eepromRecordHeader_forLookup));
+
+ l_numTests++;
+ if(l_eepromRecordHeader_realPnor->completeRecord.cached_copy_valid != 1)
+ {
+ TS_FAIL("test_invalidateCache Master Proc VPD EECACHE is expected to be valid at start of test!");
+ l_numFails++;
+ break;
+ }
+
+ // Invalidate the cache entry
+ setIsValidCacheEntry(testTarget, l_eepromRole, 0);
+
+ l_numTests++;
+ if(l_eepromRecordHeader_realPnor->completeRecord.cached_copy_valid != 0)
+ {
+ TS_FAIL("test_invalidateCache Master Proc VPD EECACHE is expected to be invalid after setIsValidCacheEntry(invalid) is called!");
+ l_numFails++;
+ break;
+ }
+
+ // Re-validate the cache entry
+ setIsValidCacheEntry(testTarget, l_eepromRole, 1);
+
+ l_numTests++;
+ if(l_eepromRecordHeader_realPnor->completeRecord.cached_copy_valid != 1)
+ {
+ TS_FAIL("test_invalidateCache Master Proc VPD EECACHE is expected to be invalid after setIsValidCacheEntry(valid) is called!");
+ l_numFails++;
+ break;
+ }
+
+ // Uncomment to verify manually
+ // printTableOfContents();
+
+ }while(0);
+
+ TRACFCOMP( g_trac_eeprom, EXIT_MRK"test_getEEPROMs numTests = %d / num fails = %d", l_numTests, l_numFails );
+ }
+
+};
+
+#endif \ No newline at end of file
diff --git a/src/usr/i2c/test/makefile b/src/usr/i2c/test/makefile
index ef774e6e0..fa9cf31c0 100644
--- a/src/usr/i2c/test/makefile
+++ b/src/usr/i2c/test/makefile
@@ -5,7 +5,7 @@
#
# OpenPOWER HostBoot Project
#
-# Contributors Listed Below - COPYRIGHT 2011,2015
+# Contributors Listed Below - COPYRIGHT 2011,2019
# [+] International Business Machines Corp.
#
#
@@ -26,6 +26,7 @@ ROOTPATH = ../../../..
MODULE = testi2c
TESTS = eepromddtest.H
+TESTS += $(if $(CONFIG_SUPPORT_EEPROM_CACHING), eecachetest.H, )
TESTS += i2ctest.H
TESTS += $(if $(CONFIG_TPMDD),tpmddtest.H,)
diff --git a/src/usr/i2c/test/tpmddtest.H b/src/usr/i2c/test/tpmddtest.H
index 8cd1fbc2c..0ea987949 100755
--- a/src/usr/i2c/test/tpmddtest.H
+++ b/src/usr/i2c/test/tpmddtest.H
@@ -111,21 +111,33 @@ class TPMDDTest: public CxxTest::TestSuite
uint32_t data = 0x0;
size_t dataSize = sizeof(data);
+ // default to most common ID
+ uint32_t expected_vendorID = TPMDD::TPM_VENDORID_65x;
+ uint8_t tpmModel = TPM_MODEL_UNDETERMINED;
+
TRACFCOMP( g_trac_tpmdd,
"testTPMReadVendorID - Start" );
do
{
-#ifdef CONFIG_AXONE_BRING_UP
- TRACFCOMP( g_trac_tpmdd,"Skipping test on Axone" );
- break;
-#endif
-
// Get a TPM Target
TARGETING::Target* testTarget = getTestTarget();
if (NULL == testTarget)
{
- continue;
+ break;
+ }
+
+ if ( !(testTarget->tryGetAttr<ATTR_TPM_MODEL>(tpmModel)) )
+ {
+ TS_FAIL("Unable to read ATTR_TPM_MODEL for %.8X target",
+ get_huid(testTarget));
+ break;
+ }
+
+ // This should match Axone and later systems
+ if (TPM_MODEL_75x == tpmModel)
+ {
+ expected_vendorID = TPMDD::TPM_VENDORID_75x;
}
num_ops++;
@@ -144,16 +156,16 @@ class TPMDDTest: public CxxTest::TestSuite
TPMDD_COMP_ID );
delete err;
err = NULL;
- continue;
+ break;
}
else if ((data & TPMDD::TPM_VENDORID_MASK)
- // Only 65x supported in simics for now:
- != TPMDD::TPM_VENDORID_65x)
+ != expected_vendorID)
{
fails++;
TS_FAIL( "testTPMReadVendorID - Failed to read "
- "correct vendor id ID=0x%X", data);
- continue;
+ "correct vendor id ID=0x%X, expected 0x%X", data,
+ expected_vendorID);
+ break;
}
else
@@ -161,7 +173,7 @@ class TPMDDTest: public CxxTest::TestSuite
TRACUCOMP(g_trac_tpmdd, "testTPMReadVendorID - "
"VendorID returned as expected. ID=0x%X",
data);
- continue;
+ break;
}
} while( 0 );
TRACFCOMP( g_trac_tpmdd,
diff --git a/src/usr/i2c/tpmdd.C b/src/usr/i2c/tpmdd.C
index a6f96514b..93aac12b9 100755
--- a/src/usr/i2c/tpmdd.C
+++ b/src/usr/i2c/tpmdd.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2019 */
+/* Contributors Listed Below - COPYRIGHT 2011,2020 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -51,7 +51,6 @@
#include <i2c/i2cif.H>
#include <secureboot/service.H>
#include <secureboot/trustedbootif.H>
-#include <scom/centaurScomCache.H> // for TRACE_ERR_FMT, TRACE_ERR_ARGS
#include "tpmdd.H"
#include "errlud_i2c.H"
OpenPOWER on IntegriCloud