summaryrefslogtreecommitdiffstats
path: root/src/usr/i2c
diff options
context:
space:
mode:
authorChristian Geddes <crgeddes@us.ibm.com>2019-01-15 09:47:31 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2019-02-13 14:41:48 -0600
commitaa18e987116a8e03391473c488d0ddb1d5ea8eb5 (patch)
treec03228ca69f31fcdf26a84f4cf15e1eb736b5164 /src/usr/i2c
parentb9678e8f9164c44361614e50cf02b6e31c860303 (diff)
downloadtalos-hostboot-aa18e987116a8e03391473c488d0ddb1d5ea8eb5.tar.gz
talos-hostboot-aa18e987116a8e03391473c488d0ddb1d5ea8eb5.zip
Add EEPROM caching device op
This commit introduces a new EEPROM_CACHE deviceOp and registers the OCMB_CHIP, PROC, and DIMM targets to it. This is part of the larger effort to transition for a "VPD" cache to an "EEPROM" cache in pnor. The deviceOp is currently called in hwasPlat's platPresenceDetect if the target in question has a ATTR_EEPROM_VPD_PRIMARY_INFO associated with it. The layout for the new EECACHE section in pnor is defined in eepromCache_const.H. Essentially it is a header that contains an array of record headers that tell where in the EECACHE pnor section a given cached EEPROM can be found. All EEPROM targets will be allocated space in the EECACHE section but only present targets will have their cache filled in. RTC: 196805 Change-Id: I49c341c9784be04ddf0259bd444f06c9baf8c6f1 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/70520 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Reviewed-by: Matt Derksen <mderkse1@us.ibm.com> Reviewed-by: Roland Veloz <rveloz@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/i2c')
-rw-r--r--src/usr/i2c/eepromCache.C540
-rwxr-xr-xsrc/usr/i2c/eepromdd.C245
-rwxr-xr-xsrc/usr/i2c/eepromdd.H6
-rw-r--r--src/usr/i2c/errlud_i2c.C2
-rwxr-xr-xsrc/usr/i2c/i2c.H1
-rw-r--r--src/usr/i2c/makefile1
6 files changed, 682 insertions, 113 deletions
diff --git a/src/usr/i2c/eepromCache.C b/src/usr/i2c/eepromCache.C
new file mode 100644
index 000000000..72541df33
--- /dev/null
+++ b/src/usr/i2c/eepromCache.C
@@ -0,0 +1,540 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/i2c/eepromCache.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2018,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 <builtins.h>
+#include <devicefw/driverif.H>
+#include "eepromdd.H"
+#include <errl/errlmanager.H>
+#include <fsi/fsiif.H>
+#include "i2c.H"
+#include <i2c/i2cif.H>
+#include <i2c/eepromif.H>
+#include <i2c/i2creasoncodes.H>
+#include <i2c/eepromCache_const.H>
+#include <initservice/initserviceif.H>
+#include <initservice/initsvcreasoncodes.H>
+#include <sys/mm.h>
+#include <limits.h>
+#include <pnor/pnorif.H>
+#include <stdarg.h>
+#include <vpd/vpd_if.H>
+
+extern trace_desc_t* g_trac_i2c;
+
+// #define TRACSSCOMP(args...) TRACFCOMP(args)
+#define TRACSSCOMP(args...)
+
+namespace I2C
+{
+
+uint64_t g_eecachePnorVaddr;
+uint64_t g_eecachePnorSize;
+
+mutex_t g_eecacheMutex = MUTEX_INITIALIZER;
+
+/**
+ * @brief Write all 0xFFs to the EECACHE section in pnor to clear out the
+ * eeprom cache information.
+ * @return errlHndl_t
+ */
+errlHndl_t clearEEcache()
+{
+ errlHndl_t l_errl = nullptr;
+
+ memset(reinterpret_cast<void *>(g_eecachePnorVaddr), 0xFF, g_eecachePnorSize);
+
+ // Flush the page to make sure it gets to the PNOR
+ int rc = mm_remove_pages( FLUSH, reinterpret_cast<void *>(g_eecachePnorVaddr), g_eecachePnorSize );
+
+
+ if( rc )
+ {
+ TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush contents write to pnor! rc=%d",rc);
+ /*@
+ * @errortype
+ * @moduleid I2C_CLEAR_EECACHE
+ * @reasoncode I2C_FAILED_TO_FLUSH_CONTENTS
+ * @userdata1 Requested Address
+ * @userdata2 rc from mm_remove_pages
+ * @devdesc clearEEcache mm_remove_pages FLUSH failed
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_CLEAR_EECACHE,
+ I2C_FAILED_TO_FLUSH_CONTENTS,
+ (uint64_t)g_eecachePnorVaddr,
+ TO_UINT64(rc),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ l_errl->collectTrace(I2C_COMP_NAME);
+ }
+ return l_errl;
+}
+
+/**
+ * @brief Lookup I2C information for given eeprom, check if eeprom exists in cache.
+ * If it exists already determine if any updates are required. If it is not
+ * in the cache yet, add it to the cache.
+ *
+ * @param[in] i_target Presence detect target
+ * @param[in] i_present Describes whether or not target is present
+ * ( CANNOT RELY ON HWAS_STATE!! )
+ * @param[in] i_eepromType Describes which EEPROM associated to the target
+ * that is being requested to cache. (PRIMARY/BACKUP etc)
+ * @return errlHndl_t
+ */
+errlHndl_t cacheEeprom(TARGETING::Target* i_target,
+ bool i_present,
+ EEPROM::eeprom_chip_types_t i_eepromType)
+{
+ TRACSSCOMP( g_trac_i2c, "cacheEeprom() ENTER Target HUID 0x%.08X ", TARGETING::get_huid(i_target));
+ errlHndl_t l_errl = nullptr;
+ TARGETING::Target * l_muxTarget = nullptr;
+ TARGETING::Target * l_i2cMasterTarget = nullptr;
+ TARGETING::TargetService& l_targetService = TARGETING::targetService();
+
+ EEPROM::eeprom_addr_t l_eepromInfo;
+ eecacheSectionHeader * l_eecacheSectionHeaderPtr;
+
+ // Initially assume we will want to update both the entry in the header
+ // as well as the contents in the body of the EECACHE section
+ bool l_updateHeader = true;
+ bool l_updateContents = true;
+
+ do{
+ // eepromReadAttributes keys off the eepromRole value
+ // to determine what attribute to lookup to get eeprom info
+ l_eepromInfo.eepromRole = i_eepromType;
+
+ l_errl = eepromReadAttributes(i_target, l_eepromInfo);
+ if(l_errl)
+ {
+ TRACFCOMP( g_trac_i2c,
+ "cacheEeprom() error occured reading eeprom attributes for eepromType %d, target 0x%.08X, returning!!",
+ i_eepromType,
+ TARGETING::get_huid(i_target));
+ l_errl->collectTrace(I2C_COMP_NAME);
+ break;
+ }
+
+ // Grab the I2C mux target so we can read the HUID, if the target is NULL we will not be able
+ // to lookup attribute to uniquely ID this eeprom so we will not cache it
+ l_muxTarget = l_targetService.toTarget( l_eepromInfo.i2cMuxPath);
+ if(l_muxTarget == nullptr)
+ {
+ TRACFCOMP( g_trac_i2c,
+ "cacheEeprom() Mux target associated with target 0x%.08X resolved to a nullptr , check attribute for eepromType %d. Skipping Cache",
+ TARGETING::get_huid(i_target),
+ i_eepromType);
+ /*@
+ * @errortype
+ * @moduleid I2C_CACHE_EEPROM
+ * @reasoncode I2C_MUX_TARGET_NOT_FOUND
+ * @userdata1 HUID of target we want to cache
+ * @userdata2[0:31] Type of EEPROM we are caching
+ * @userdata2[32:63] Boolean is target present or not
+ * @devdesc cacheEeprom invalid mux target
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_CACHE_EEPROM,
+ I2C_MUX_TARGET_NOT_FOUND,
+ TARGETING::get_huid(i_target),
+ TWO_UINT32_TO_UINT64(i_eepromType, i_present),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ l_errl->collectTrace(I2C_COMP_NAME);
+ break;
+ }
+
+ // Grab the I2C master target so we can read the HUID, if the target is NULL we will not be able
+ // to lookup attribute to uniquely ID this eeprom so we will not cache it
+ l_i2cMasterTarget = l_targetService.toTarget( l_eepromInfo.i2cMasterPath );
+ if(l_i2cMasterTarget == nullptr)
+ {
+ TRACFCOMP( g_trac_i2c,
+ "cacheEeprom() I2C Master target associated with target 0x%.08X resolved to a nullptr , check attribute for eepromType %d. Skipping Cache ",
+ TARGETING::get_huid(i_target),
+ i_eepromType);
+ /*@
+ * @errortype
+ * @moduleid I2C_CACHE_EEPROM
+ * @reasoncode INVALID_MASTER_TARGET
+ * @userdata1 HUID of target we want to cache
+ * @userdata2[0:31] Type of EEPROM we are caching
+ * @userdata2[32:63] Boolean is target present or not
+ * @devdesc cacheEeprom invalid master target
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_CACHE_EEPROM,
+ INVALID_MASTER_TARGET,
+ TARGETING::get_huid(i_target),
+ TWO_UINT32_TO_UINT64(i_eepromType, i_present),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ l_errl->collectTrace(I2C_COMP_NAME);
+ break;
+ }
+
+ // if g_eecachePnorVaddr == 0 this indicates we have not yet looked up
+ // the virtual address for the start of the EECACHE pnor section so we must look
+ // it up. We can then store it in this global var for later use
+ if(g_eecachePnorVaddr == 0 || g_eecachePnorSize == 0)
+ {
+ PNOR::SectionInfo_t l_sectionInfo;
+ l_errl = PNOR::getSectionInfo(PNOR::EECACHE, l_sectionInfo);
+
+ if(l_errl)
+ {
+ TRACFCOMP( g_trac_i2c, "cacheEeprom() Failed while looking up the EECACHE section in PNOR!!");
+ break;
+ }
+
+ mutex_lock(&g_eecacheMutex);
+ g_eecachePnorVaddr = l_sectionInfo.vaddr;
+ g_eecachePnorSize = l_sectionInfo.size;
+ TRACFCOMP( g_trac_i2c, "cacheEeprom() vaddr for EECACHE start = 0x%lx , size = 0x%lx!!",
+ g_eecachePnorVaddr, g_eecachePnorSize);
+ mutex_unlock(&g_eecacheMutex);
+ }
+
+ // The start of the EECACHE pnor section follows the order of the eecacheSectionHeader struct
+ // that is defined in eepromCache_const.H. This should be the version, followed by the current
+ // end of the cache, followed by a list of EEPROM entries that combines huid of mux target, huid
+ // of master target, port of eeprom, and devAddr of eeprom to come up with a unqiue identifier
+ // for a given eeprom.
+ l_eecacheSectionHeaderPtr = reinterpret_cast<eecacheSectionHeader*>(g_eecachePnorVaddr);
+
+ if(l_eecacheSectionHeaderPtr->version == EECACHE_VERSION_UNSET)
+ {
+ // If version == 0xFF then nothing has been cached before,
+ // if nothing has been cached before then version should
+ // be set to be the latest version of the struct available
+ l_eecacheSectionHeaderPtr->version = EECACHE_VERSION_LATEST;
+ TRACFCOMP( g_trac_i2c,
+ "cacheEeprom() Found Empty Cache, set version of cache structure to be 0x%.02x",
+ EECACHE_VERSION_1);
+ }
+
+ if(l_eecacheSectionHeaderPtr->end_of_cache == UNSET_END_OF_CACHE_VALUE)
+ {
+ // If end_of_cache == 0xFFFFFFFF then we will assume the cache is empty.
+ // In this case, we must set end_of_cache to be the end of the header.
+ // This means the start of first eeprom's cached data will be immediately
+ // following the end of the EECACHE header.
+ l_eecacheSectionHeaderPtr->end_of_cache = sizeof(eecacheSectionHeader);
+ TRACFCOMP( g_trac_i2c,
+ "cacheEeprom() Found Empty Cache, set end of cache to be 0x%.04x (End of ToC)",
+ sizeof(eecacheSectionHeader));
+ }
+
+ // This is what we will compare w/ when we are going through the existing
+ // caches in the eeprom to see if we have already cached something
+ // Or if no matches are found we will copy this into the header
+ eepromRecordHeader l_eepromRecord = {l_i2cMasterTarget->getAttr<TARGETING::ATTR_HUID>(),
+ (uint8_t)l_eepromInfo.port,
+ (uint8_t)l_eepromInfo.engine,
+ (uint8_t)l_eepromInfo.devAddr,
+ l_muxTarget->getAttr<TARGETING::ATTR_HUID>(),
+ l_eepromInfo.i2cMuxBusSelector,
+ (uint8_t)l_eepromInfo.devSize_KB,
+ 0, // Default internal offset to be 0
+ i_present};
+
+ size_t l_eepromLen = l_eepromInfo.devSize_KB * KILOBYTE;
+
+ // Parse through PNOR section header to determine if a copy of this
+ // eeprom already exists, or if we need to add it, and where we should add it
+ // if we need to.
+ eepromRecordHeader * l_recordHeaderToUpdate;
+
+ // Initialize this to an INVALID value. This way we catch the case where
+ // cache has 50 records and we cannot add anymore. In that case l_recordHeaderToUpdateIndex
+ // would not get set in the loop below.
+ uint8_t l_recordHeaderToUpdateIndex = INVALID_EEPROM_INDEX;
+
+ for(uint8_t i = 0; i < MAX_EEPROMS_VERSION_1; i++)
+ {
+ // Keep track of current record so we can use outside for loop
+ l_recordHeaderToUpdate = &l_eecacheSectionHeaderPtr->recordHeaders[i];
+
+ // If internal_offset is non-zero then we will assume this address has been filled
+ if(l_recordHeaderToUpdate->internal_offset != UNSET_INTERNAL_OFFSET_VALUE)
+ {
+ // Compare the eeprom record we are checking against the eeprom records we are iterating through
+ // but ignore the last 9 bytes which have chip size, the offset into this pnor section where the
+ // record exists, and a byte that tells us if its valid or not
+ if( memcmp(l_recordHeaderToUpdate, &l_eepromRecord, RECORD_COMPARE_SIZE ) == 0 )
+ {
+ l_recordHeaderToUpdateIndex = i;
+ if( l_recordHeaderToUpdate->record_size != l_eepromRecord.record_size)
+ {
+ // This indicates that a part size has changed , caching
+ // algorithm cannot account for size changes.
+ // Invalidate entire cache and TI to trigger re-ipl
+ l_errl = clearEEcache();
+
+ // If there was an error clearing the cache commit is because we are TIing
+ if(l_errl)
+ {
+ errlCommit(l_errl, I2C_COMP_ID);
+ }
+
+ INITSERVICE::doShutdown(INITSERVICE::SHUTDOWN_DO_RECONFIG_LOOP);
+ }
+
+ if(l_recordHeaderToUpdate->record_valid)
+ {
+ // If the existing eeprom record is valid, then only update the
+ // contents if the SN/PN for current HW do not match the eeprom
+ // record. (target must be present to cache)
+
+ // TODO RTC:203788 add lookup for PN and SN matches
+ //if( !i_present || PNandSNMatch )
+ {
+ l_updateContents = false;
+ }
+
+ // If target is present there is nothing in the
+ // header to update
+ if( i_present )
+ {
+ l_updateHeader = false;
+ }
+ }
+ else if(!i_present)
+ {
+ // If the target is not present, then do not update contents or header
+ l_updateContents = false;
+ l_updateHeader = false;
+ }
+
+ TRACSSCOMP( g_trac_i2c, "cacheEeprom() already found copy for eeprom role %d for target w/ HUID 0x.%08X",
+ i_eepromType , TARGETING::get_huid(i_target));
+ break;
+ }
+ }
+ else
+ {
+ assert((l_eecacheSectionHeaderPtr->end_of_cache + l_eepromLen) < g_eecachePnorSize,
+ "Sum of system EEPROMs is larger than space allocated for EECACHE pnor section");
+
+ l_recordHeaderToUpdateIndex = i;
+ // Set this new eepromRecord's offset within the EECACHE PNOR section
+ // to be the current "end of cache" offset in the toc.
+ l_eepromRecord.internal_offset = l_eecacheSectionHeaderPtr->end_of_cache;
+ l_eecacheSectionHeaderPtr->end_of_cache += l_eepromLen;
+ l_updateContents = i_present;
+ break;
+ }
+ }
+
+
+ // 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 )
+ {
+ assert(l_recordHeaderToUpdateIndex != INVALID_EEPROM_INDEX,
+ "More than MAX_EEPROMS_VERSION_1 in system XML");
+
+ void * l_tmpBuffer;
+
+ l_tmpBuffer = malloc(l_eepromLen);
+
+ void * l_internalSectionAddr =
+ reinterpret_cast<uint8_t *>(l_eecacheSectionHeaderPtr) + l_eepromRecord.internal_offset;
+
+ TRACSSCOMP( g_trac_i2c, "cacheEeprom() passing the following into deviceOp eeprom address : huid 0x%.08X length 0x%.08X" ,
+ get_huid(i_target), l_eepromLen);
+
+ // Copy vpd contents to cache
+ l_errl = deviceOp(DeviceFW::READ,
+ i_target,
+ l_tmpBuffer,
+ l_eepromLen,
+ DEVICE_EEPROM_ADDRESS(i_eepromType, 0));
+
+ // If an error occurred during the eeprom read then free the tmp buffer and break out
+ if( l_errl)
+ {
+ TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error occured reading from EEPROM type %d for HUID 0x%.08X!",
+ i_eepromType,get_huid(i_target));
+ free(l_tmpBuffer);
+ break;
+ }
+
+ // Copy from tmp buffer into vaddr of internal section offset
+ memcpy(l_internalSectionAddr, l_tmpBuffer, l_eepromLen);
+
+ // Flush the page to make sure it gets to the PNOR
+ int rc = mm_remove_pages( FLUSH, l_internalSectionAddr, l_eepromLen );
+ if( rc )
+ {
+ TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush contents write to pnor! rc=%d",rc);
+ /*@
+ * @errortype
+ * @moduleid I2C_CACHE_EEPROM
+ * @reasoncode I2C_FAILED_TO_FLUSH_CONTENTS
+ * @userdata1 Requested Address
+ * @userdata2 rc from mm_remove_pages
+ * @devdesc cacheEeprom mm_remove_pages FLUSH failed
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_CACHE_EEPROM,
+ I2C_FAILED_TO_FLUSH_CONTENTS,
+ (uint64_t)l_internalSectionAddr,
+ TO_UINT64(rc),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ }
+ else
+ {
+ TRACSSCOMP( g_trac_i2c, "cacheEeprom() %.08X bytes of eeprom data related to %.08X have been written to %p" ,
+ l_eepromLen, get_huid(i_target), l_internalSectionAddr);
+ }
+
+ // regardless of success always free tmp buffer we allocated
+ free(l_tmpBuffer);
+
+ if(l_errl)
+ {
+ break;
+ }
+
+ }
+
+ // Above we have determined whether the header entry for the eeprom at
+ // hand needs to be updated. Only do the following steps that update
+ // the eeprom's header entry if we were told to do so.
+ if(l_updateHeader)
+ {
+ // Copy the local eepromRecord header struct with the info about the
+ // new eeprom we want to add to the cache to the open slot we found
+ memcpy(l_recordHeaderToUpdate , &l_eepromRecord, sizeof(eepromRecordHeader));
+
+ // Flush the page to make sure it gets to the PNOR
+ int rc = mm_remove_pages( FLUSH, l_recordHeaderToUpdate, sizeof(eepromRecordHeader) );
+ if( rc )
+ {
+ TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush header write to pnor, rc=%d",rc);
+ /*@
+ * @errortype
+ * @moduleid I2C_CACHE_EEPROM
+ * @reasoncode I2C_FAILED_TO_FLUSH_HEADER
+ * @userdata1 Requested Address
+ * @userdata2 rc from mm_remove_pages
+ * @devdesc cacheEeprom mm_remove_pages FLUSH failed
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ I2C_CACHE_EEPROM,
+ I2C_FAILED_TO_FLUSH_HEADER,
+ (uint64_t)l_recordHeaderToUpdate,
+ TO_UINT64(rc),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ break;
+ }
+ }
+
+ TRACDBIN( g_trac_i2c, "cacheEeprom: l_eecacheSectionHeaderPtr currently ",
+ l_eecacheSectionHeaderPtr,
+ sizeof(eecacheSectionHeader));
+ }while(0);
+
+ TRACSSCOMP( g_trac_i2c, "cacheEeprom() EXIT Target HUID 0x%.08X ", TARGETING::get_huid(i_target));
+
+ return l_errl;
+}
+
+/**
+ * @brief Generic deviceOp that will lookup the PRIMARY_VPD eeprom associated
+ * with a given target and cache the data from the eeprom into the
+ * EECACHE section in PNOR for later use
+ *
+ * @param[in] i_opType Operation type, see DeviceFW::OperationType
+ * in driverif.H
+ * @param[in] i_target Target whose Eeprom we will try to cache
+ * @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 genericI2CEepromCache(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;
+
+ // First param is a uint64_t representing if the target is present or not
+ bool l_present = (bool)va_arg(i_args,uint64_t);
+
+ // second param is the type of EEPROM type we wish to cache (PRIMARY vs BACKUP etc)
+ EEPROM::eeprom_chip_types_t l_eepromType = (EEPROM::eeprom_chip_types_t)va_arg(i_args,uint64_t);
+
+ TRACSSCOMP( g_trac_i2c, ENTER_MRK"genericI2CEepromCache() "
+ "Target HUID 0x%.08X Enter", TARGETING::get_huid(i_target));
+
+ do{
+ // Run the cache eerpom function on the target passed in
+ l_errl = cacheEeprom(i_target, l_present, l_eepromType);
+ if(l_errl)
+ {
+ TRACFCOMP(g_trac_i2c,
+ ERR_MRK"cacheEeprom: An error occured while attempting to cache eeprom for 0x%.08X",
+ TARGETING::get_huid(i_target));
+ break;
+ }
+
+ }while(0);
+
+ TRACSSCOMP( g_trac_i2c, EXIT_MRK"genericI2CEepromCache() "
+ "Target HUID 0x%.08X EXIT", TARGETING::get_huid(i_target));
+
+ return l_errl;
+}
+
+DEVICE_REGISTER_ROUTE( DeviceFW::READ,
+ DeviceFW::EEPROM_CACHE,
+ TARGETING::TYPE_OCMB_CHIP,
+ genericI2CEepromCache);
+
+DEVICE_REGISTER_ROUTE( DeviceFW::READ,
+ DeviceFW::EEPROM_CACHE,
+ TARGETING::TYPE_PROC,
+ genericI2CEepromCache );
+
+DEVICE_REGISTER_ROUTE( DeviceFW::READ,
+ DeviceFW::EEPROM_CACHE,
+ TARGETING::TYPE_DIMM,
+ genericI2CEepromCache );
+
+} \ No newline at end of file
diff --git a/src/usr/i2c/eepromdd.C b/src/usr/i2c/eepromdd.C
index 048cd731a..c14180a3a 100755
--- a/src/usr/i2c/eepromdd.C
+++ b/src/usr/i2c/eepromdd.C
@@ -119,11 +119,18 @@ DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
TARGETING::TYPE_NODE,
eepromPerformOp );
+// Register the perform Op with the routing code for MCS chiplets.
DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
DeviceFW::EEPROM,
TARGETING::TYPE_MCS,
eepromPerformOp );
+// Register the perform Op with the routing code for Open-Capi Memory Buffer Chips.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::EEPROM,
+ TARGETING::TYPE_OCMB_CHIP,
+ eepromPerformOp );
+
/**
*
@@ -197,7 +204,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
TARGETING::Target * i2cMasterTarget = NULL;
eeprom_addr_t i2cInfo;
- i2cInfo.chip = va_arg( i_args, uint64_t );
+ i2cInfo.eepromRole = va_arg( i_args, uint64_t );
i2cInfo.offset = va_arg( i_args, uint64_t );
TRACDCOMP( g_trac_eeprom,
@@ -205,7 +212,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
TRACUCOMP (g_trac_eeprom, ENTER_MRK"eepromPerformOp(): "
"i_opType=%d, chip=%d, offset=%x, len=%d",
- (uint64_t) i_opType, i2cInfo.chip, i2cInfo.offset, io_buflen);
+ (uint64_t) i_opType, i2cInfo.eepromRole, i2cInfo.offset, io_buflen);
#ifdef __HOSTBOOT_RUNTIME
// At runtime the OCC sensor cache will need to be diabled to avoid I2C
@@ -250,7 +257,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
TRACFCOMP( g_trac_eeprom,
ERR_MRK"eepromPerformOp(): Device Overflow! "
"C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X "
- "devSizeKB=0x%X", i2cInfo.chip, i2cInfo.engine,
+ "devSizeKB=0x%X", i2cInfo.eepromRole, i2cInfo.engine,
i2cInfo.port, i2cInfo.devAddr, i2cInfo.offset,
io_buflen, i2cInfo.devSize_KB);
@@ -296,11 +303,13 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
TRACFCOMP( g_trac_eeprom,
"eepromPerformOp(): i_opType=%d "
- "C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X, "
- "snglChipKB=0x%X, chipCount=0x%X, devSizeKB=0x%X", i_opType,
- i2cInfo.chip, i2cInfo.engine, i2cInfo.port, i2cInfo.devAddr,
- i2cInfo.offset, io_buflen, l_snglChipSize,
- i2cInfo.chipCount, i2cInfo.devSize_KB);
+ "C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X, ",
+ i_opType, i2cInfo.eepromRole, i2cInfo.engine,
+ i2cInfo.port, i2cInfo.devAddr, i2cInfo.offset, io_buflen)
+
+ TRACFCOMP (g_trac_eeprom,
+ "eepromPerformOp(): snglChipKB=0x%X, chipCount=0x%X, devSizeKB=0x%X",
+ l_snglChipSize, i2cInfo.chipCount, i2cInfo.devSize_KB);
// Printing mux info separately, if combined, nothing is displayed
char* l_muxPath = i2cInfo.i2cMuxPath.toString();
@@ -360,7 +369,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
EEPROM_PERFORM_OP,
EEPROM_INVALID_OPERATION,
i_opType,
- i2cInfo.chip,
+ i2cInfo.eepromRole,
true /*Add HB SW Callout*/ );
err->collectTrace( EEPROM_COMP_NAME );
@@ -453,7 +462,7 @@ bool eepromPresence ( TARGETING::Target * i_target )
eeprom_addr_t i2cInfo;
- i2cInfo.chip = EEPROM::VPD_PRIMARY;
+ i2cInfo.eepromRole = EEPROM::VPD_PRIMARY;
i2cInfo.offset = 0;
do
{
@@ -657,88 +666,49 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
"EEPROM READ START : Chip: %02d : Offset %.2X : Len %d",
i_i2cInfo.chip, i_i2cInfo.offset, i_buflen );
-
- // Check to see if the Read operation straddles the EEPROM page
- //boundary
- l_boundaryCrossed = crossesEepromPageBoundary( i_i2cInfo.offset,
- i_buflen,
- l_readBuflen,
- l_pageTwoBuflen,
- i_i2cInfo );
-
- // Set addressing parameters
- err = eepromPrepareAddress( i_target,
- &byteAddr,
- byteAddrSize,
- l_desiredPage,
- i_i2cInfo);
-
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- ERR_MRK"eepromRead()::eepromPrepareAddress()");
- break;
- }
-
-
- // Attempt to lock page mutex
- bool l_switchPage = true;
- bool l_lockMutex = true;
- err = eepromPageOp( i_target,
- l_switchPage,
- l_lockMutex,
- l_pageLocked,
- l_desiredPage,
- i_i2cInfo );
-
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- "eepromRead()::eepromPageOp()::failed locking page");
- break;
- }
+ // At maximum we want to do 1 KB reads at a time. The largest that
+ // the scom byte range will support is 64 KB - 1 but we will do 1
+ // KB at a time to catch fails faster. This is useful when we do big
+ // reads when caching the eeprom to pnor.
+ size_t l_readLenRemaining = i_buflen;
+ size_t l_currentReadLen;
// Lock to sequence operations
mutex_lock( &g_eepromMutex );
-
- // First Read. If Second read is necessary, this call will read
- // everything from the original offset up to the 256th byte
- err = eepromReadData( i_target,
- o_buffer,
- l_readBuflen,
- &byteAddr,
- byteAddrSize,
- i_i2cInfo );
- if( err )
- {
- TRACFCOMP(g_trac_eeprom,
- "Failed reading data: original read");
- break;
- }
-
-
- // Perform the second Read if necessary. Read starts at
- // begining of EEPROM page 1 (offset=0x100) and reads the
- // rest of the required data.
- if( l_boundaryCrossed )
+
+ while( l_readLenRemaining > 0 )
{
- //Prepare the address to read at the start of EEPROM page one
- i_i2cInfo.offset = EEPROM_PAGE_SIZE; // 0x100
+ l_currentReadLen = l_readLenRemaining < KILOBYTE ? l_readLenRemaining : KILOBYTE;
+
+ // Check to see if the Read operation straddles the EEPROM page
+ // boundary.Note this is only required for systems w/ DDR4 industry
+ // standard dimms. DDR4 ISDIMMS have a max of 512 bytes so we will
+ // never loop through this multiple times on those systems
+ l_boundaryCrossed = crossesEepromPageBoundary( i_i2cInfo.offset,
+ l_currentReadLen,
+ l_readBuflen,
+ l_pageTwoBuflen,
+ i_i2cInfo );
+
+ // Set addressing parameters
err = eepromPrepareAddress( i_target,
&byteAddr,
byteAddrSize,
l_desiredPage,
- i_i2cInfo );
+ i_i2cInfo);
+
if( err )
{
TRACFCOMP(g_trac_eeprom,
- "Error preparing address: second eeprom read");
+ ERR_MRK"eepromRead()::eepromPrepareAddress()");
break;
}
- // Switch to the second EEPROM page
- l_switchPage = true;
- l_lockMutex = false;
+
+ // Attempt to lock page mutex
+ // (only important in DDR4 IS-DIMM systems)
+ bool l_switchPage = true;
+ bool l_lockMutex = true;
err = eepromPageOp( i_target,
l_switchPage,
l_lockMutex,
@@ -748,32 +718,89 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
if( err )
{
- TRACFCOMP( g_trac_eeprom,
- "Failed switching to EEPROM page 1 for second read op");
+ TRACFCOMP(g_trac_eeprom,
+ "eepromRead()::eepromPageOp()::failed locking page");
break;
}
- // Perform the second read operation
- err = eepromReadData(
- i_target,
- &(reinterpret_cast<uint8_t*>(o_buffer)[l_readBuflen]),
- l_pageTwoBuflen,
- &byteAddr,
- byteAddrSize,
- i_i2cInfo );
+ // First Read. If Second read is necessary, this call will read
+ // everything from the original offset up to the 256th byte
+ err = eepromReadData( i_target,
+ &(reinterpret_cast<uint8_t*>(o_buffer)[i_buflen - l_readLenRemaining]),
+ l_readBuflen,
+ &byteAddr,
+ byteAddrSize,
+ i_i2cInfo );
+
+ i_i2cInfo.offset += l_currentReadLen;
+ l_readLenRemaining -= l_currentReadLen;
if( err )
{
- TRACFCOMP( g_trac_eeprom,
- "Failed reading data: second read");
+ TRACFCOMP(g_trac_eeprom,
+ "Failed reading data: original read");
break;
}
+
+
+ // Perform the second Read if necessary. Read starts at
+ // begining of EEPROM page 1 (offset=0x100) and reads the
+ // rest of the required data.
+ if( l_boundaryCrossed )
+ {
+ //Prepare the address to read at the start of EEPROM page one
+ i_i2cInfo.offset = EEPROM_PAGE_SIZE; // 0x100
+ err = eepromPrepareAddress( i_target,
+ &byteAddr,
+ byteAddrSize,
+ l_desiredPage,
+ i_i2cInfo );
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "Error preparing address: second eeprom read");
+ break;
+ }
+
+ // Switch to the second EEPROM page
+ l_switchPage = true;
+ l_lockMutex = false;
+ err = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "Failed switching to EEPROM page 1 for second read op");
+ break;
+ }
+
+ // Perform the second read operation
+ err = eepromReadData(
+ i_target,
+ &(reinterpret_cast<uint8_t*>(o_buffer)[l_readBuflen]),
+ l_pageTwoBuflen,
+ &byteAddr,
+ byteAddrSize,
+ i_i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "Failed reading data: second read");
+ break;
+ }
+ }
}
TRACUCOMP( g_trac_eepromr,
- "EEPROM READ END : Chip: %02d : Offset %.2X : Len %d : %016llx",
- i_i2cInfo.chip, i_i2cInfo.offset, i_buflen,
+ "EEPROM READ END : Eeprom Role: %02d : Offset %.2X : Len %d : %016llx",
+ i_i2cInfo.eepromRole, i_i2cInfo.offset, i_buflen,
*((uint64_t*)o_buffer) );
} while( 0 );
@@ -1035,8 +1062,8 @@ errlHndl_t eepromWrite ( TARGETING::Target * i_target,
do
{
TRACUCOMP( g_trac_eeprom,
- "EEPROM WRITE START : Chip: %02d : Offset %.2X : Len %d : %016llx",
- i_i2cInfo.chip, i_i2cInfo.offset, io_buflen,
+ "EEPROM WRITE START : Eeprom Role : %02d : Offset %.2X : Len %d : %016llx",
+ i_i2cInfo.eepromRole, i_i2cInfo.offset, io_buflen,
*((uint64_t*)io_buffer) );
@@ -1094,7 +1121,7 @@ errlHndl_t eepromWrite ( TARGETING::Target * i_target,
EEPROM_WRITE,
EEPROM_I2C_WRITE_PAGE_SIZE_ZERO,
TARGETING::get_huid(i_target),
- i_i2cInfo.chip,
+ i_i2cInfo.eepromRole,
true /*Add HB SW Callout*/ );
err->collectTrace( EEPROM_COMP_NAME );
@@ -1237,8 +1264,8 @@ errlHndl_t eepromWrite ( TARGETING::Target * i_target,
TRACSCOMP( g_trac_eepromr,
- "EEPROM WRITE END : Chip: %02d : Offset %.2X : Len %d",
- i_i2cInfo.chip, i_i2cInfo.offset, io_buflen );
+ "EEPROM WRITE END : Eeprom Role : %02d : Offset %.2X : Len %d",
+ i_i2cInfo.eepromRole, i_i2cInfo.offset, io_buflen );
} while( 0 );
// Free memory
@@ -1541,7 +1568,7 @@ errlHndl_t eepromPrepareAddress ( TARGETING::Target * i_target,
EEPROM_PREPAREADDRESS,
EEPROM_INVALID_DEVICE_TYPE,
i_i2cInfo.addrSize,
- i_i2cInfo.chip,
+ i_i2cInfo.eepromRole,
true /*Add HB SW Callout*/ );
err->collectTrace( EEPROM_COMP_NAME );
@@ -1579,7 +1606,7 @@ errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
do
{
- switch (o_i2cInfo.chip )
+ switch (o_i2cInfo.eepromRole )
{
case VPD_PRIMARY:
if( !( i_target->
@@ -1628,7 +1655,7 @@ errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
default:
TRACFCOMP( g_trac_eeprom,ERR_MRK"eepromReadAttributes() - "
"Invalid chip (%d) to read attributes from!",
- o_i2cInfo.chip );
+ o_i2cInfo.eepromRole );
/*@
* @errortype
@@ -1642,7 +1669,7 @@ errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
EEPROM_READATTRIBUTES,
EEPROM_INVALID_CHIP,
- o_i2cInfo.chip,
+ o_i2cInfo.eepromRole,
TARGETING::get_huid(i_target),
true /*Add HB SW Callout*/ );
@@ -1656,8 +1683,8 @@ errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
{
TRACFCOMP( g_trac_eeprom,
ERR_MRK"eepromReadAttributes() - ERROR reading "
- "attributes for chip %d!",
- o_i2cInfo.chip );
+ "attributes for eeprom role %d!",
+ o_i2cInfo.eepromRole );
/*@
* @errortype
@@ -1673,7 +1700,7 @@ errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
EEPROM_READATTRIBUTES,
EEPROM_ATTR_INFO_NOT_FOUND,
TARGETING::get_huid(i_target),
- o_i2cInfo.chip);
+ o_i2cInfo.eepromRole);
// Could be FSP or HB code's fault
err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
@@ -1749,12 +1776,14 @@ errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
} while( 0 );
TRACUCOMP(g_trac_eeprom,"eepromReadAttributes() tgt=0x%X, %d/%d/0x%X "
- "wpw=0x%X, dsKb=0x%X, chpCnt=%d, aS=%d (%d), wct=%d",
+ "wpw=0x%X, dsKb=0x%X, chpCnt=%d, aS=%d (%d)",
TARGETING::get_huid(i_target),
o_i2cInfo.port, o_i2cInfo.engine, o_i2cInfo.devAddr,
o_i2cInfo.writePageSize, o_i2cInfo.devSize_KB,
o_i2cInfo.chipCount, o_i2cInfo.addrSize,
- eepromData.byteAddrOffset, o_i2cInfo.writeCycleTime);
+ eepromData.byteAddrOffset);
+
+
// Printing mux info separately, if combined, nothing is displayed
char* l_muxPath = o_i2cInfo.i2cMuxPath.toString();
@@ -1836,7 +1865,7 @@ errlHndl_t eepromGetI2CMasterTarget ( TARGETING::Target * i_target,
EEPROM_GETI2CMASTERTARGET,
EEPROM_I2C_MASTER_PATH_ERROR,
TWO_UINT32_TO_UINT64(
- i_i2cInfo.chip,
+ i_i2cInfo.eepromRole,
TARGETING::get_huid(i_target) ),
l_epCompressed,
true /*Add HB SW Callout*/ );
@@ -1891,7 +1920,7 @@ errlHndl_t eepromGetI2CMasterTarget ( TARGETING::Target * i_target,
EEPROM_GETI2CMASTERTARGET,
EEPROM_TARGET_NULL,
TWO_UINT32_TO_UINT64(
- i_i2cInfo.chip,
+ i_i2cInfo.eepromRole,
TARGETING::get_huid(i_target) ),
l_epCompressed,
true /*Add HB SW Callout*/ );
diff --git a/src/usr/i2c/eepromdd.H b/src/usr/i2c/eepromdd.H
index 1dddb0b0e..8acf7d8f2 100755
--- a/src/usr/i2c/eepromdd.H
+++ b/src/usr/i2c/eepromdd.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2018 */
+/* Contributors Listed Below - COPYRIGHT 2011,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -62,7 +62,7 @@ struct eeprom_addr_t
uint64_t port;
uint64_t engine;
uint64_t devAddr;
- int64_t chip;
+ int64_t eepromRole;
uint64_t offset;
eeprom_addr_size_t addrSize;
TARGETING::EntityPath i2cMasterPath;
@@ -80,7 +80,7 @@ struct eeprom_addr_t
: port(0),
engine(0),
devAddr(0),
- chip(0),
+ eepromRole(0),
offset(0),
addrSize(LAST_DEVICE_TYPE),
i2cMasterPath(),
diff --git a/src/usr/i2c/errlud_i2c.C b/src/usr/i2c/errlud_i2c.C
index 7c3e00f12..bd27be102 100644
--- a/src/usr/i2c/errlud_i2c.C
+++ b/src/usr/i2c/errlud_i2c.C
@@ -262,7 +262,7 @@ UdEepromParms::UdEepromParms( uint8_t i_opType,
memcpy(l_pBuf, &tmp64, sizeof(tmp64));
l_pBuf += sizeof(tmp64);
- tmp64 = i_i2cInfo.chip;
+ tmp64 = i_i2cInfo.eepromRole;
memcpy(l_pBuf, &tmp64, sizeof(tmp64));
l_pBuf += sizeof(tmp64);
diff --git a/src/usr/i2c/i2c.H b/src/usr/i2c/i2c.H
index 114e5a554..baf95df32 100755
--- a/src/usr/i2c/i2c.H
+++ b/src/usr/i2c/i2c.H
@@ -959,7 +959,6 @@ void setLogicalFsiEnginePort(size_t &io_logical_engine,
void addHwCalloutsI2c(errlHndl_t i_err,
TARGETING::Target * i_target,
const misc_args_t & i_args);
-
}; // end I2C namespace
#endif // __I2C_H
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
OpenPOWER on IntegriCloud