diff options
Diffstat (limited to 'src')
28 files changed, 3328 insertions, 2602 deletions
diff --git a/src/build/configs/simics_axone.config b/src/build/configs/simics_axone.config index 1a9ff72b6..a71f5e2f7 100644 --- a/src/build/configs/simics_axone.config +++ b/src/build/configs/simics_axone.config @@ -1,11 +1,12 @@ set DJVPD_READ_FROM_HW +# You can enabled MVPD read from HW but adds time to IPL +#set MVPD_READ_FROM_HW + #skip enabling checkstop analysis until OCC is ready in simics unset IPLTIME_CHECKSTOP_ANALYSIS -#Try to keep a list of things this does -# - skipping setting voltages in istep 8.12, nothing on other side of AVSbus -# in simics currently. set AXONE_BRING_UP -set SUPPORT_EEPROM_CACHING
\ No newline at end of file +set SUPPORT_EEPROM_CACHING + diff --git a/src/build/simics/standalone.simics b/src/build/simics/standalone.simics index 8ad8e89e4..c34dfc794 100755 --- a/src/build/simics/standalone.simics +++ b/src/build/simics/standalone.simics @@ -40,26 +40,41 @@ if ($hb_skip_vpd_preload == 0) { # If Axone and Beyond, load VPD into DDIMM VPD if ($hb_mode == 0){ - $dimmSpd = $hb_script_location + "/dimmspd.dat" + $dimmSpd = $hb_script_location + "/dimmspd.dat" + $procMvpd = "/gsa/rchgsa/home/c/r/crgeddes/documents/hbBuild/procvpd.dat" + + proc_hb0.seeprom0_image.load-file $procMvpd + echo " - loaded MVPD to seeprom0" + + proc_hb0.seeprom2_image.load-file $procMvpd + echo " - loaded MVPD to seeprom2" ddimm0.VPD_0_image.load-file $dimmSpd - echo " - loaded SPD to DDIMM0" + echo " - loaded SPD to DDIMM0" + ddimm1.VPD_0_image.load-file $dimmSpd - echo " - loaded SPD to DDIMM1" + echo " - loaded SPD to DDIMM1" + ddimm2.VPD_0_image.load-file $dimmSpd - echo " - loaded SPD to DDIMM2" + echo " - loaded SPD to DDIMM2" + ddimm3.VPD_0_image.load-file $dimmSpd - echo " - loaded SPD to DDIMM3" + echo " - loaded SPD to DDIMM3" + ddimm4.VPD_0_image.load-file $dimmSpd - echo " - loaded SPD to DDIMM4" + echo " - loaded SPD to DDIMM4" + ddimm5.VPD_0_image.load-file $dimmSpd - echo " - loaded SPD to DDIMM5" + echo " - loaded SPD to DDIMM5" + ddimm6.VPD_0_image.load-file $dimmSpd - echo " - loaded SPD to DDIMM6" + echo " - loaded SPD to DDIMM6" + ddimm7.VPD_0_image.load-file $dimmSpd - echo " - loaded SPD to DDIMM7" + echo " - loaded SPD to DDIMM7" + ddimm8.VPD_0_image.load-file $dimmSpd - echo " - loaded SPD to DDIMM8" + echo " - loaded SPD to DDIMM8" } # Turn on all processor cec-chips diff --git a/src/include/usr/devicefw/userif.H b/src/include/usr/devicefw/userif.H index 523537cfb..d626d49c0 100644 --- a/src/include/usr/devicefw/userif.H +++ b/src/include/usr/devicefw/userif.H @@ -326,12 +326,14 @@ namespace DeviceFW /** * Construct the device addressing parameters for the EEPROM device ops. * @param[in] i_eeprom_enum - The chip number of the EEPROM to access. See - * eeprom_chip_types_t in eepromif.H + * EEPROM_ROLE in eeprom_const.H * @param[in] i_offset - The internal offset of the EEPROM slave device. + * @param[in] i_deviceSelect - Choose which device you want to perform op on: + * AUTOSELECT , CACHE, or HARDWARE */ - #define DEVICE_EEPROM_ADDRESS( i_eeprom_enum, i_offset )\ + #define DEVICE_EEPROM_ADDRESS( i_eeprom_enum, i_offset, i_deviceSelect )\ DeviceFW::EEPROM, static_cast<uint64_t>(( i_eeprom_enum )),\ - static_cast<uint64_t>(( i_offset )) + static_cast<uint64_t>(( i_offset )), static_cast<uint64_t>((i_deviceSelect)) /** * Construct the device addressing parameters for the TPM device ops. diff --git a/src/include/usr/errl/errli2c.H b/src/include/usr/errl/errli2c.H index bc1617e13..3875c9f4e 100644 --- a/src/include/usr/errl/errli2c.H +++ b/src/include/usr/errl/errli2c.H @@ -62,7 +62,7 @@ struct I2cMatchingInfo_t uint8_t port; uint8_t devAddr; uint8_t chipCount; - EEPROM::eeprom_chip_types_t chipType; + EEPROM::EEPROM_ROLE chipType; const TARGETING::Target* tgt; uint8_t targetAncestryDepth; }; diff --git a/src/include/usr/i2c/eepromCache_const.H b/src/include/usr/i2c/eepromCache_const.H deleted file mode 100644 index e94798b79..000000000 --- a/src/include/usr/i2c/eepromCache_const.H +++ /dev/null @@ -1,73 +0,0 @@ -/* IBM_PROLOG_BEGIN_TAG */ -/* This is an automatically generated prolog. */ -/* */ -/* $Source: src/include/usr/i2c/eepromCache_const.H $ */ -/* */ -/* OpenPOWER HostBoot Project */ -/* */ -/* Contributors Listed Below - COPYRIGHT 2019 */ -/* [+] International Business Machines Corp. */ -/* */ -/* */ -/* Licensed under the Apache License, Version 2.0 (the "License"); */ -/* you may not use this file except in compliance with the License. */ -/* You may obtain a copy of the License at */ -/* */ -/* http://www.apache.org/licenses/LICENSE-2.0 */ -/* */ -/* Unless required by applicable law or agreed to in writing, software */ -/* distributed under the License is distributed on an "AS IS" BASIS, */ -/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ -/* implied. See the License for the specific language governing */ -/* permissions and limitations under the License. */ -/* */ -/* IBM_PROLOG_END_TAG */ -#ifndef EEPROM_CACHE_CONST_H -#define __EEPROM_CACHE_CONST_H - -constexpr uint8_t MAX_EEPROMS_VERSION_1 = 50; -constexpr uint8_t INVALID_EEPROM_INDEX = 0xFF; -constexpr uint32_t UNSET_INTERNAL_OFFSET_VALUE = 0xFFFFFFFF; -constexpr uint32_t UNSET_END_OF_CACHE_VALUE = UNSET_INTERNAL_OFFSET_VALUE; - -enum EECACHE_VERSION -{ - EECACHE_VERSION_UNSET = 0xFF, - EECACHE_VERSION_1 = 0x01, - EECACHE_VERSION_LATEST = EECACHE_VERSION_1, -}; - -enum EEPROM_ATTRIBUTE_MASK : uint8_t -{ - HAS_EEPROM_NV_INFO = 0x01, - HAS_EEPROM_SBE_BACKUP_INFO = 0x02, - HAS_EEPROM_SBE_PRIMARY_INFO = 0x04, - HAS_EEPROM_VPD_BACKUP_INFO = 0x08, - HAS_EEPROM_VPD_PRIMARY_INFO = 0x10, -}; - - -struct eepromRecordHeader -{ - uint32_t target_huid; - uint8_t port; - uint8_t engine; - uint8_t devAddr; - uint32_t mux_huid; - uint8_t mux_select; - uint32_t record_size; - uint32_t internal_offset; - uint8_t record_valid; -} PACKED ; - //record_size // internal_offset //record_valid -constexpr size_t RECORD_COMPARE_SIZE = sizeof(eepromRecordHeader) - sizeof(uint32_t) - sizeof(uint32_t) - sizeof(uint8_t); - -struct eecacheSectionHeader -{ - uint8_t version; - uint32_t end_of_cache; - eepromRecordHeader recordHeaders[MAX_EEPROMS_VERSION_1]; -} PACKED ; - - -#endif
\ No newline at end of file diff --git a/src/include/usr/i2c/eeprom_const.H b/src/include/usr/i2c/eeprom_const.H new file mode 100644 index 000000000..e9e157757 --- /dev/null +++ b/src/include/usr/i2c/eeprom_const.H @@ -0,0 +1,239 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/usr/i2c/eeprom_const.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2019 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __EEPROM_CONST_H +#define __EEPROM_CONST_H + +#include <devicefw/driverif.H> +#include <targeting/common/entitypath.H> +#include <string.h> + +namespace EEPROM +{ + +// Hardware OP related consts +constexpr uint16_t EEPROM_PAGE_SIZE = 0x100; +constexpr uint8_t EEPROM_DEVADDR_INC = 2; +constexpr uint8_t MAX_BYTE_ADDR = 2; +constexpr uint8_t EEPROM_MAX_RETRIES = 2; + +// EECACHE OP related consts +constexpr uint8_t INVALID_EEPROM_INDEX = 0xFF; +constexpr uint32_t UNSET_INTERNAL_OFFSET_VALUE = 0xFFFFFFFF; +constexpr uint32_t UNSET_END_OF_CACHE_VALUE = UNSET_INTERNAL_OFFSET_VALUE; +constexpr uint8_t NUM_BYTE_UNIQUE_ID = 12; +constexpr uint8_t MAX_EEPROMS_VERSION_1 = 50; + +/** + * @brief Enumerations to link EEPROM types to EEPROM's chip number behind + * a device +*/ +enum EEPROM_ROLE +{ + VPD_PRIMARY = 0, + VPD_BACKUP = 1, + SBE_PRIMARY = 2, + SBE_BACKUP = 3, + LAST_CHIP_TYPE, + // Useful Enums + INVALID_CHIP_TYPE = LAST_CHIP_TYPE, + FIRST_CHIP_TYPE = VPD_PRIMARY +}; + +/** + * @brief Enumerations to help direct if we want to perform a given op on + * the eeprom cache in pnor or the actual hardware. Or if the user + * wants the driver to determine if reading from cache is possible, and + * if not fall back to doing the op on HW (AUTOSELECT) +*/ +enum EEPROM_SOURCE +{ + AUTOSELECT = 0x0000, + CACHE = 0x0001, + HARDWARE = 0x0002, +}; + +/** +* @brief Enumerations to describe the type of devices to be accessed. +*/ +typedef enum +{ + ZERO_BYTE_ADDR = 0, + ONE_BYTE_ADDR_PAGESELECT = 1, // page select + TWO_BYTE_ADDR = 2, + ONE_BYTE_ADDR = 3, + LAST_DEVICE_TYPE +} eeprom_addr_size_t; + +/** +* @brief Enumerations to describe version of the eepromRecordHeader +* and eecacheSectionHeader structs +*/ +enum EECACHE_VERSION +{ + EECACHE_VERSION_UNSET = 0xFF, + EECACHE_VERSION_1 = 0x01, + // Useful Enum + EECACHE_VERSION_LATEST = EECACHE_VERSION_1, +}; + +/** +* @brief Handy union of two structs which represents the layout +* of bits to describe a record in the EECACHE ToC. The +* EECACHE ToC will have room for multiple of these record +* headers. +* +* completeRecord is the standard way to access data in the union. +* +* uniqueRecord is useful if you want to quickly compare the "unique" +* bits of a header entry which includes the target_huid, port, engine, +* devAddr, mux_huid, and mux_select. +* +*/ +union eepromRecordHeader +{ + struct completeRecord + { + uint32_t i2c_master_huid; // HUID of i2c Master + uint8_t port; // I2C Port + uint8_t engine; // I2C Engine + uint8_t devAddr; // I2C Device Address + uint8_t mux_select; // Some I2C devices are behind a mux, this says + // what setting on the mux is required + uint32_t cache_copy_size; // Size of data saved in cache (in KB) + uint32_t internal_offset; // offset from start of EECACHE section where cached + // data exists + uint8_t cached_copy_valid; // if == 0 , cached data is invalid + } PACKED completeRecord; + + struct uniqueRecord + { + uint8_t uniqueID [NUM_BYTE_UNIQUE_ID]; + uint8_t metaData [sizeof(completeRecord) - NUM_BYTE_UNIQUE_ID]; + } PACKED uniqueRecord; + + inline bool operator<(const eepromRecordHeader& rhs) const{ + return memcmp(this->uniqueRecord.uniqueID, rhs.uniqueRecord.uniqueID, NUM_BYTE_UNIQUE_ID) < 0; + } + + // Default ctor + eepromRecordHeader() + { + memset(this, 0, sizeof(eepromRecordHeader)); + }; + +} PACKED; + +/** +* @brief Struct which represents the Table of Contents (ToC) for +* the EECACHE section in pnor +* +*/ +struct eecacheSectionHeader +{ + uint8_t version; // EECACHE_VERSION + uint32_t end_of_cache; // End point of the last cache entry + eepromRecordHeader recordHeaders[MAX_EEPROMS_VERSION_1]; +} PACKED ; + +/** + * @brief Structure of common parameters describing a unqiue eeprom. + * This is used all over the eeprom code, often functions will + * fill in information they know and pass on the struct. + * + * Some functions require fields to be filled in prior to being + * passed to said function. + */ +struct eeprom_addr_t +{ + uint64_t port; + uint64_t engine; + uint64_t devAddr; + int64_t eepromRole; + uint64_t offset; + eeprom_addr_size_t addrSize; + TARGETING::EntityPath i2cMasterPath; + uint64_t writePageSize; // in bytes + uint64_t devSize_KB; // in kilobytes + uint64_t chipCount; // number of chips making up eeprom device + uint64_t writeCycleTime; // in milliseconds + uint8_t i2cMuxBusSelector; + TARGETING::EntityPath i2cMuxPath; + + /** + * @brief Construct a default eeprom_addr_t + */ + eeprom_addr_t() + : port(0), + engine(0), + devAddr(0), + eepromRole(INVALID_CHIP_TYPE), + offset(0), + addrSize(LAST_DEVICE_TYPE), + i2cMasterPath(TARGETING::EntityPath::PATH_NA), + writePageSize(0), + devSize_KB(0), + chipCount(0), + writeCycleTime(0), + i2cMuxBusSelector(I2C_MUX::NOT_APPLICABLE), + i2cMuxPath(TARGETING::EntityPath::PATH_NA) + { + } +}; + + +/** + * @brief Define a set of information about all EEPROMs in the + * system (primarily used to populate HDAT) + */ +struct EepromInfo_t +{ + TARGETING::Target* i2cMaster; //< I2C Master chip + uint64_t engine; //< I2C engine (relative to master chip) + uint64_t port; //< I2C port (relative to engine) + uint64_t busFreq; //< Bus speed in Hz + uint64_t devAddr; //< I2C device address (relative to port) + uint64_t sizeKB; //< Total eeprom size in KB + uint64_t chipCount; //< Number of chips making up eeprom device + uint64_t addrBytes; //< Number of bytes required for addressing + EEPROM_ROLE device; //< Identifies role of eeprom + TARGETING::Target* assocTarg; //< Target associated with this device + + EepromInfo_t() + : i2cMaster(nullptr), + engine(0), + port(0), + busFreq(0), + devAddr(0), + sizeKB(0), + chipCount(0), + addrBytes(0), + device(INVALID_CHIP_TYPE), + assocTarg(nullptr) + { + } +}; + +} +#endif
\ No newline at end of file diff --git a/src/include/usr/i2c/eepromddreasoncodes.H b/src/include/usr/i2c/eepromddreasoncodes.H index 454d10851..a2c7b1c83 100644 --- a/src/include/usr/i2c/eepromddreasoncodes.H +++ b/src/include/usr/i2c/eepromddreasoncodes.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* Contributors Listed Below - COPYRIGHT 2011,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -54,6 +54,9 @@ enum eepromModuleId EEPROM_PREPAREADDRESS = 0x04, EEPROM_READATTRIBUTES = 0x05, EEPROM_GETI2CMASTERTARGET = 0x06, + EEPROM_CACHE_EEPROM = 0x07, + EEPROM_CLEAR_EECACHE = 0x08, + EEPROM_CACHE_PERFORM_OP = 0x09, }; /** @@ -74,12 +77,22 @@ enum eepromReasonCode EEPROM_INVALID_ADDR_OFFSET_SIZE = EEPROM_COMP_ID | 0x07, EEPROM_OVERFLOW_ERROR = EEPROM_COMP_ID | 0x08, EEPROM_I2C_WRITE_PAGE_SIZE_ZERO = EEPROM_COMP_ID | 0x09, + EEPROM_FAILED_TO_FLUSH_CONTENTS = EEPROM_COMP_ID | 0x0A, // Error occured while trying to flush the mmio pages out + // containing contents of an EEPROM's cached data in the EECACHE + // PNOR section + EEPROM_FAILED_TO_FLUSH_HEADER = EEPROM_COMP_ID | 0x0B, // Error occured while trying to flush the mmio page out + // containing EECACHE header the to pnor + EEPROM_I2C_MUX_PATH_ERROR = EEPROM_COMP_ID | 0x0C, + EEPROM_NOT_IN_CACHE = EEPROM_COMP_ID | 0x0D, + EEPROM_NEW_DEVICE_DETECTED = EEPROM_COMP_ID | 0x0E, // While looking up a part, found that current EEPROM size does not + // match what we have seen in previous IPLs indicating a new part has + // been installed on the system. }; enum UserDetailsTypes { - EEPROM_UDT_NO_FORMAT = 0x0, - EEPROM_UDT_PARAMETERS = 0x1, + EEPROM_UDT_NO_FORMAT = 0x0, + EEPROM_UDT_PARAMETERS = 0x1, }; }; // end EEPROM diff --git a/src/include/usr/i2c/eepromif.H b/src/include/usr/i2c/eepromif.H index 62618e195..63b8422f3 100644 --- a/src/include/usr/i2c/eepromif.H +++ b/src/include/usr/i2c/eepromif.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -26,35 +26,12 @@ #define __EEPROMIF_H #include <list> +#include <i2c/eeprom_const.H> namespace EEPROM { /** - * @brief Enumerations to link EEPROM types to EEPROM's chip number behind - * a device -*/ -typedef enum -{ - VPD_PRIMARY = 0, - VPD_BACKUP = 1, - SBE_PRIMARY = 2, - SBE_BACKUP = 3, - LAST_CHIP_TYPE, - INVALID_CHIP_TYPE = LAST_CHIP_TYPE, - FIRST_CHIP_TYPE = VPD_PRIMARY -} eeprom_chip_types_t; - -/* - * @brief Miscellaneous enums for EEPROM - */ -enum -{ - EEPROM_PAGE_SIZE = 0x100, - EEPROM_DEVADDR_INC = 2 -}; - -/** * @brief This function tests to see if the VPD_PRIMARY eeprom is present * for the specific target. * @@ -65,26 +42,49 @@ enum bool eepromPresence ( TARGETING::Target * i_target ); /** - * @brief Define a set of information about all EEPROMs in the - * system (primarily used to populate HDAT) + * @brief this function will read all of the associated attributes needed + * to access the intended EEPROM. These attributes will be used to + * determine the type of I2C device as well as how to address it via + * the I2C device driver. + * + * @param[in] i_target - Target device. + * + * @param[out] o_i2cInfo - The structure that will contain the attribute data + * read from the target device. + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to the + * error log. */ -struct EepromInfo_t -{ - TARGETING::Target* i2cMaster; //< I2C Master chip - uint64_t engine; //< I2C engine (relative to master chip) - uint64_t port; //< I2C port (relative to engine) - uint64_t busFreq; //< Bus speed in Hz - uint64_t devAddr; //< I2C device address (relative to port) - uint64_t sizeKB; //< Total eeprom size in KB - uint64_t chipCount; //< Number of chips making up eeprom device - uint64_t addrBytes; //< Number of bytes required for addressing - eeprom_chip_types_t device; //< Identifies role of eeprom - TARGETING::Target* assocTarg; //< Target associated with this device -}; +errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target, + eeprom_addr_t & o_i2cInfo ); + + +/** + * @brief This function determines whether or not the i2cMasterPath provided + * along with i_i2cInfo points to a valid target. If it does not, + * o_target will result as NULL. If the target is valid then the + * o_target will point to the target pointer which i2cMasterPath + * represents. + * + * @param[in] i_target - The current Target. + * + * @param[in] i_i2cInfo - Structure of I2C parameters needed to execute + * the command to the I2C device driver. + * NOTE: it is expected i2cMasterPath member is filled out + * + * @param[out] o_target - The "new" target that will be used for all operations + * from this point on. + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to the + * error log. + */ +errlHndl_t eepromGetI2CMasterTarget ( TARGETING::Target * i_target, + const eeprom_addr_t & i_i2cInfo, + TARGETING::Target * &o_target ); /** * @brief Return a set of information related to every unique - * EEPROM in the system + * EEPROM in the system (currently used to build HDAT structure) * * @param[out] o_info - list of EEPROM Information * @@ -93,6 +93,26 @@ struct EepromInfo_t */ void getEEPROMs( std::list<EepromInfo_t>& o_info ); +/** + * + * @brief A useful utility to dump (trace out) the EepromVpdPrimaryInfo data. + * Use as needed. + * + * @param [in] i_i2cInfo - The EepromVpdPrimaryInfo data to dump for user + * + */ +void dumpEepromData(const TARGETING::EepromVpdPrimaryInfo & i_i2cInfo); + +/** + * + * @brief A useful utility to dump (trace out) the eeprom_addr_t data. + * Use as needed. + * + * @param [in] i_i2cInfo - The eeprom_addr_t data to dump for user + * + */ +void dumpEepromData(const eeprom_addr_t & i_i2cInfo); + }; // end namespace EEPROM #endif // end __EEPROMIF_H diff --git a/src/include/usr/i2c/i2creasoncodes.H b/src/include/usr/i2c/i2creasoncodes.H index a723e4ec8..6b08aefc2 100644 --- a/src/include/usr/i2c/i2creasoncodes.H +++ b/src/include/usr/i2c/i2creasoncodes.H @@ -66,8 +66,6 @@ enum i2cModuleId READ_I2C_ATTRIBUTES = 0x10, I2C_ACCESS_MUX = 0x11, I2C_GENERIC_PRES_DETECT = 0x12, - I2C_CACHE_EEPROM = 0x13, - I2C_CLEAR_EECACHE = 0x14, }; @@ -103,11 +101,7 @@ enum i2cReasonCode I2C_MUX_TARGET_NON_FUNCTIONAL = I2C_COMP_ID | 0x15, // The MUX target is non functional I2C_INVALID_LENGTH = I2C_COMP_ID | 0x16, // Invalid data buffer length passed to function I2C_NULL_MASTER_TARGET = I2C_COMP_ID | 0x17, // Target Service's toPath() returned nullptr for target - I2C_FAILED_TO_FLUSH_CONTENTS = I2C_COMP_ID | 0x18, // Error occured while trying to flush the mmio pages out - // containing contents of an EEPROM's cached data in the EECACHE - // PNOR section - I2C_FAILED_TO_FLUSH_HEADER = I2C_COMP_ID | 0x19, // Error occured while trying to flush the mmio page out -}; // containing EECACHE header the to pnor +}; enum UserDetailsTypes diff --git a/src/include/usr/sbe/sbe_update.H b/src/include/usr/sbe/sbe_update.H index f4dc648b7..b388c4cae 100644 --- a/src/include/usr/sbe/sbe_update.H +++ b/src/include/usr/sbe/sbe_update.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -31,7 +31,7 @@ #include <errl/errlentry.H> // errlHndl_t #include <errl/hberrltypes.H> // ERRORLOG::errlSeverity_t #include <targeting/common/target.H> // Target -#include <i2c/eepromif.H> // eeprom_chip_types_t +#include <i2c/eepromif.H> // EEPROM_ROLE #include <pnor/ecc.H> // PNOR::ECC::eccStatus #include <util/utilxipimage.H> // Util::imageBuild_t #include <p9_infrastruct_help.H> // MAX_RING_BUF_SIZE, etc @@ -175,7 +175,7 @@ namespace SBE // Update Fields and New Fields to be Written to the Target sbeUpdateActions_t update_actions; - EEPROM::eeprom_chip_types_t seeprom_side_to_update; + EEPROM::EEPROM_ROLE seeprom_side_to_update; sbeSeepromVersionInfo_t new_seeprom_ver; bool new_readBack_check; @@ -342,7 +342,7 @@ namespace SBE * @return errlHndl_t Error log handle on failure. */ errlHndl_t getSeepromSideVersionViaI2c(TARGETING::Target* i_target, - EEPROM::eeprom_chip_types_t i_seepromSide, + EEPROM::EEPROM_ROLE i_seepromSide, sbeSeepromVersionInfo_t& o_info, bool& o_seeprom_ver_ECC_fail); /** diff --git a/src/include/usr/sbe/sbeif.H b/src/include/usr/sbe/sbeif.H index 022be1d72..0fa909f4a 100644 --- a/src/include/usr/sbe/sbeif.H +++ b/src/include/usr/sbe/sbeif.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -146,7 +146,7 @@ namespace SBE * @return errlHndl_t Error log handle on failure; otherwise nullptr */ errlHndl_t getHwKeyHashFromSbeImage(TARGETING::Target* i_target, - EEPROM::eeprom_chip_types_t i_seeprom, + EEPROM::EEPROM_ROLE i_seeprom, sbeSeepromSide_t i_bootSide, SHA512_t o_hash, const void * i_image_ptr = nullptr); diff --git a/src/usr/hdat/hdatutil.C b/src/usr/hdat/hdatutil.C index 6c141065c..d0b3edca1 100644 --- a/src/usr/hdat/hdatutil.C +++ b/src/usr/hdat/hdatutil.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2018 */ +/* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -1672,7 +1672,9 @@ errlHndl_t hdatGetFullEepromVpd(TARGETING::Target * i_target, i_target, o_data, io_dataSize, - DEVICE_EEPROM_ADDRESS(EEPROM::VPD_PRIMARY, 0)); + DEVICE_EEPROM_ADDRESS(EEPROM::VPD_PRIMARY, + 0, + EEPROM::AUTOSELECT)); if(err) { HDAT_ERR("Reading Full vpd from Eeprom failed"); diff --git a/src/usr/i2c/eepromCache.C b/src/usr/i2c/eepromCache.C index 72541df33..dc8bb15db 100644 --- a/src/usr/i2c/eepromCache.C +++ b/src/usr/i2c/eepromCache.C @@ -24,176 +24,239 @@ /* IBM_PROLOG_END_TAG */ #include <builtins.h> +#include <stdarg.h> +#include <sys/mm.h> +#include <limits.h> #include <devicefw/driverif.H> -#include "eepromdd.H" #include <errl/errlmanager.H> #include <fsi/fsiif.H> #include "i2c.H" +#include "eepromCache.H" #include <i2c/i2cif.H> #include <i2c/eepromif.H> -#include <i2c/i2creasoncodes.H> -#include <i2c/eepromCache_const.H> +#include <i2c/eepromddreasoncodes.H> #include <initservice/initserviceif.H> #include <initservice/initsvcreasoncodes.H> -#include <sys/mm.h> -#include <limits.h> #include <pnor/pnorif.H> -#include <stdarg.h> #include <vpd/vpd_if.H> +#include <errl/errludtarget.H> -extern trace_desc_t* g_trac_i2c; +extern trace_desc_t* g_trac_eeprom; -// #define TRACSSCOMP(args...) TRACFCOMP(args) +//#define TRACSSCOMP(args...) TRACFCOMP(args) #define TRACSSCOMP(args...) -namespace I2C +namespace EEPROM { -uint64_t g_eecachePnorVaddr; -uint64_t g_eecachePnorSize; - +// Global variable that will keep track of the virtual address which +// points to the start of the EECACHE section, and the size of this section. +// It is handy to keep these around so we do not need to look them up in the +// pnor code everytime. +uint64_t g_eecachePnorVaddr = 0; +uint64_t g_eecachePnorSize = 0; + +// Global map which is used as a way to quickly look up the virtual address +// of a given eeprom's cached data in EECACHE section +// Key = eepromRecordHeader with unique info filled out +// Value = virtual address pointing to the cached eeprom data in pnor +std::map<eepromRecordHeader, uint64_t> g_cachedEeproms; + +// Any time we access either any of the global variables defined above we want +// to wrap the call in this mutex to avoid multi-threading issues mutex_t g_eecacheMutex = MUTEX_INITIALIZER; -/** - * @brief Write all 0xFFs to the EECACHE section in pnor to clear out the - * eeprom cache information. - * @return errlHndl_t - */ -errlHndl_t clearEEcache() +uint64_t lookupEepromAddr(const eepromRecordHeader& i_eepromRecordHeader) { - errlHndl_t l_errl = nullptr; - - memset(reinterpret_cast<void *>(g_eecachePnorVaddr), 0xFF, g_eecachePnorSize); - - // Flush the page to make sure it gets to the PNOR - int rc = mm_remove_pages( FLUSH, reinterpret_cast<void *>(g_eecachePnorVaddr), g_eecachePnorSize ); + uint64_t l_vaddr = 0; + std::map<eepromRecordHeader, uint64_t>::iterator l_it; + // Wrap lookup in mutex because reads are not thread safe + mutex_lock(&g_eecacheMutex); + l_it = g_cachedEeproms.find(i_eepromRecordHeader); + mutex_unlock(&g_eecacheMutex); - if( rc ) + if(l_it != g_cachedEeproms.end()) { - TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush contents write to pnor! rc=%d",rc); - /*@ - * @errortype - * @moduleid I2C_CLEAR_EECACHE - * @reasoncode I2C_FAILED_TO_FLUSH_CONTENTS - * @userdata1 Requested Address - * @userdata2 rc from mm_remove_pages - * @devdesc clearEEcache mm_remove_pages FLUSH failed - */ - l_errl = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_UNRECOVERABLE, - I2C_CLEAR_EECACHE, - I2C_FAILED_TO_FLUSH_CONTENTS, - (uint64_t)g_eecachePnorVaddr, - TO_UINT64(rc), - ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); - - l_errl->collectTrace(I2C_COMP_NAME); + l_vaddr = l_it->second; } - return l_errl; + return l_vaddr; } -/** - * @brief Lookup I2C information for given eeprom, check if eeprom exists in cache. - * If it exists already determine if any updates are required. If it is not - * in the cache yet, add it to the cache. - * - * @param[in] i_target Presence detect target - * @param[in] i_present Describes whether or not target is present - * ( CANNOT RELY ON HWAS_STATE!! ) - * @param[in] i_eepromType Describes which EEPROM associated to the target - * that is being requested to cache. (PRIMARY/BACKUP etc) - * @return errlHndl_t - */ -errlHndl_t cacheEeprom(TARGETING::Target* i_target, - bool i_present, - EEPROM::eeprom_chip_types_t i_eepromType) +errlHndl_t buildEepromRecordHeader(TARGETING::Target * i_target, + eeprom_addr_t & io_eepromInfo, + eepromRecordHeader & o_eepromRecordHeader) { - TRACSSCOMP( g_trac_i2c, "cacheEeprom() ENTER Target HUID 0x%.08X ", TARGETING::get_huid(i_target)); - errlHndl_t l_errl = nullptr; + TARGETING::Target * l_muxTarget = nullptr; TARGETING::Target * l_i2cMasterTarget = nullptr; TARGETING::TargetService& l_targetService = TARGETING::targetService(); - - EEPROM::eeprom_addr_t l_eepromInfo; - eecacheSectionHeader * l_eecacheSectionHeaderPtr; - - // Initially assume we will want to update both the entry in the header - // as well as the contents in the body of the EECACHE section - bool l_updateHeader = true; - bool l_updateContents = true; + errlHndl_t l_errl = nullptr; do{ - // eepromReadAttributes keys off the eepromRole value - // to determine what attribute to lookup to get eeprom info - l_eepromInfo.eepromRole = i_eepromType; - l_errl = eepromReadAttributes(i_target, l_eepromInfo); + l_errl = eepromReadAttributes(i_target, io_eepromInfo); if(l_errl) { - TRACFCOMP( g_trac_i2c, - "cacheEeprom() error occured reading eeprom attributes for eepromType %d, target 0x%.08X, returning!!", - i_eepromType, + TRACFCOMP( g_trac_eeprom, + "buildEepromRecordHeader() error occured reading eeprom attributes for eepromType %d, target 0x%.08X, returning!!", + io_eepromInfo.eepromRole, TARGETING::get_huid(i_target)); - l_errl->collectTrace(I2C_COMP_NAME); + l_errl->collectTrace(EEPROM_COMP_NAME); break; } // Grab the I2C mux target so we can read the HUID, if the target is NULL we will not be able // to lookup attribute to uniquely ID this eeprom so we will not cache it - l_muxTarget = l_targetService.toTarget( l_eepromInfo.i2cMuxPath); + l_muxTarget = l_targetService.toTarget( io_eepromInfo.i2cMuxPath); if(l_muxTarget == nullptr) { - TRACFCOMP( g_trac_i2c, - "cacheEeprom() Mux target associated with target 0x%.08X resolved to a nullptr , check attribute for eepromType %d. Skipping Cache", + TRACFCOMP( g_trac_eeprom, + "buildEepromRecordHeader() Mux target associated with target 0x%.08X resolved to a nullptr , check attribute for eepromType %d. Skipping Cache", TARGETING::get_huid(i_target), - i_eepromType); + io_eepromInfo.eepromRole); /*@ * @errortype - * @moduleid I2C_CACHE_EEPROM - * @reasoncode I2C_MUX_TARGET_NOT_FOUND + * @moduleid EEPROM_CACHE_EEPROM + * @reasoncode EEPROM_I2C_MUX_PATH_ERROR * @userdata1 HUID of target we want to cache - * @userdata2[0:31] Type of EEPROM we are caching - * @userdata2[32:63] Boolean is target present or not - * @devdesc cacheEeprom invalid mux target + * @userdata2 Type of EEPROM we are caching + * @devdesc buildEepromRecordHeader invalid mux target */ l_errl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - I2C_CACHE_EEPROM, - I2C_MUX_TARGET_NOT_FOUND, + EEPROM_CACHE_EEPROM, + EEPROM_I2C_MUX_PATH_ERROR, TARGETING::get_huid(i_target), - TWO_UINT32_TO_UINT64(i_eepromType, i_present), + io_eepromInfo.eepromRole, ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); - l_errl->collectTrace(I2C_COMP_NAME); + l_errl->collectTrace(EEPROM_COMP_NAME); break; } // Grab the I2C master target so we can read the HUID, if the target is NULL we will not be able // to lookup attribute to uniquely ID this eeprom so we will not cache it - l_i2cMasterTarget = l_targetService.toTarget( l_eepromInfo.i2cMasterPath ); + l_i2cMasterTarget = l_targetService.toTarget( io_eepromInfo.i2cMasterPath ); if(l_i2cMasterTarget == nullptr) { - TRACFCOMP( g_trac_i2c, - "cacheEeprom() I2C Master target associated with target 0x%.08X resolved to a nullptr , check attribute for eepromType %d. Skipping Cache ", + TRACFCOMP( g_trac_eeprom, + "buildEepromRecordHeader() I2C Master target associated with target 0x%.08X resolved to a nullptr , check attribute for eepromType %d. Skipping Cache ", TARGETING::get_huid(i_target), - i_eepromType); + io_eepromInfo.eepromRole); /*@ * @errortype - * @moduleid I2C_CACHE_EEPROM - * @reasoncode INVALID_MASTER_TARGET + * @moduleid EEPROM_CACHE_EEPROM + * @reasoncode EEPROM_I2C_MASTER_PATH_ERROR * @userdata1 HUID of target we want to cache - * @userdata2[0:31] Type of EEPROM we are caching - * @userdata2[32:63] Boolean is target present or not - * @devdesc cacheEeprom invalid master target + * @userdata2 Type of EEPROM we are caching + * @devdesc buildEepromRecordHeader invalid master target */ l_errl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - I2C_CACHE_EEPROM, - INVALID_MASTER_TARGET, + EEPROM_CACHE_EEPROM, + EEPROM_I2C_MASTER_PATH_ERROR, TARGETING::get_huid(i_target), - TWO_UINT32_TO_UINT64(i_eepromType, i_present), + io_eepromInfo.eepromRole, ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); - l_errl->collectTrace(I2C_COMP_NAME); + l_errl->collectTrace(EEPROM_COMP_NAME); + break; + } + + // This is what we will compare w/ when we are going through the existing + // caches in the eeprom to see if we have already cached something + // Or if no matches are found we will copy this into the header + o_eepromRecordHeader.completeRecord.i2c_master_huid = l_i2cMasterTarget->getAttr<TARGETING::ATTR_HUID>(); + o_eepromRecordHeader.completeRecord.port = static_cast<uint8_t>(io_eepromInfo.port); + o_eepromRecordHeader.completeRecord.engine = static_cast<uint8_t>(io_eepromInfo.engine); + o_eepromRecordHeader.completeRecord.devAddr = static_cast<uint8_t>(io_eepromInfo.devAddr); + o_eepromRecordHeader.completeRecord.mux_select = static_cast<uint8_t>(io_eepromInfo.i2cMuxBusSelector); + o_eepromRecordHeader.completeRecord.cache_copy_size = static_cast<uint32_t>(io_eepromInfo.devSize_KB); + + // Do not set valid bit nor internal offset here as we do not have + // enough information availible to determine + + }while(0); + + return l_errl; +} + +// Do NOT allow adding/removing eeproms to cache during RT +#ifndef __HOSTBOOT_RUNTIME + +bool addEepromToCachedList(const eepromRecordHeader & i_eepromRecordHeader) +{ + bool l_matchFound = true; + std::map<eepromRecordHeader, uint64_t>::iterator it; + + // Map accesses are not thread safe, make sure this is always wrapped in mutex + mutex_lock(&g_eecacheMutex); + + if(g_cachedEeproms.find(i_eepromRecordHeader) == g_cachedEeproms.end()) + { + g_cachedEeproms[i_eepromRecordHeader] = g_eecachePnorVaddr + i_eepromRecordHeader.completeRecord.internal_offset; + TRACSSCOMP( g_trac_eeprom, "addEepromToCachedList() Adding I2CM Huid: 0x%.08X, Port: 0x%.02X, Engine: 0x%.02X, Dev Addr: 0x%.02X, Mux Select: 0x%.02X, Size: 0x%.08X to g_cachedEeproms", + i_eepromRecordHeader.completeRecord.i2c_master_huid, + i_eepromRecordHeader.completeRecord.port, + i_eepromRecordHeader.completeRecord.engine, + i_eepromRecordHeader.completeRecord.devAddr, + i_eepromRecordHeader.completeRecord.mux_select, + i_eepromRecordHeader.completeRecord.cache_copy_size); + l_matchFound = false; + } + + mutex_unlock(&g_eecacheMutex); + + return l_matchFound; +} + +/** + * @brief Lookup I2C information for given eeprom, check if eeprom exists in cache. + * If it exists already determine if any updates are required. If it is not + * in the cache yet, add it to the cache. + * + * @param[in] i_target Presence detect target + * @param[in] i_present Describes whether or not target is present + * ( CANNOT RELY ON HWAS_STATE!! ) + * @param[in] i_eepromType Describes which EEPROM associated to the target + * that is being requested to cache. (PRIMARY/BACKUP etc) + * @return errlHndl_t + */ +errlHndl_t cacheEeprom(TARGETING::Target* i_target, + bool i_present, + EEPROM::EEPROM_ROLE i_eepromType) +{ + TRACSSCOMP( g_trac_eeprom, "cacheEeprom() ENTER Target HUID 0x%.08X ", TARGETING::get_huid(i_target)); + errlHndl_t l_errl = nullptr; + + EEPROM::eeprom_addr_t l_eepromInfo; + eecacheSectionHeader * l_eecacheSectionHeaderPtr; + eepromRecordHeader l_eepromRecordHeader; + + // Initially assume we will want to update both the entry in the header + // as well as the contents in the body of the EECACHE section + bool l_updateHeader = true; + bool l_updateContents = true; + + do{ + // eepromReadAttributes keys off the eepromRole value + // to determine what attribute to lookup to get eeprom info + l_eepromInfo.eepromRole = i_eepromType; + + // if the target is present, then this record is valid + l_eepromRecordHeader.completeRecord.cached_copy_valid = i_present; + + // buildEepromRecordHeader will call eepromReadAttributes to fill in l_eepromInfo + // with info looked up in attributes and also fill in l_eepromRecordHeader + l_errl = buildEepromRecordHeader(i_target, l_eepromInfo, l_eepromRecordHeader); + + TRACDBIN( g_trac_eeprom, "cacheEeprom: l_eepromRecordHeader currently ", + &l_eepromRecordHeader, + sizeof(eepromRecordHeader)); + + if(l_errl) + { + // buildEepromRecordHeader should have traced any relavent information if + // is was needed, just break out and pass the error along break; } @@ -207,14 +270,14 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target, if(l_errl) { - TRACFCOMP( g_trac_i2c, "cacheEeprom() Failed while looking up the EECACHE section in PNOR!!"); + TRACFCOMP( g_trac_eeprom, "cacheEeprom() Failed while looking up the EECACHE section in PNOR!!"); break; } mutex_lock(&g_eecacheMutex); g_eecachePnorVaddr = l_sectionInfo.vaddr; g_eecachePnorSize = l_sectionInfo.size; - TRACFCOMP( g_trac_i2c, "cacheEeprom() vaddr for EECACHE start = 0x%lx , size = 0x%lx!!", + TRACFCOMP( g_trac_eeprom, "cacheEeprom() vaddr for EECACHE start = 0x%lx , size = 0x%lx!!", g_eecachePnorVaddr, g_eecachePnorSize); mutex_unlock(&g_eecacheMutex); } @@ -232,7 +295,7 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target, // if nothing has been cached before then version should // be set to be the latest version of the struct available l_eecacheSectionHeaderPtr->version = EECACHE_VERSION_LATEST; - TRACFCOMP( g_trac_i2c, + TRACFCOMP( g_trac_eeprom, "cacheEeprom() Found Empty Cache, set version of cache structure to be 0x%.02x", EECACHE_VERSION_1); } @@ -244,30 +307,17 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target, // This means the start of first eeprom's cached data will be immediately // following the end of the EECACHE header. l_eecacheSectionHeaderPtr->end_of_cache = sizeof(eecacheSectionHeader); - TRACFCOMP( g_trac_i2c, + TRACFCOMP( g_trac_eeprom, "cacheEeprom() Found Empty Cache, set end of cache to be 0x%.04x (End of ToC)", sizeof(eecacheSectionHeader)); } - // This is what we will compare w/ when we are going through the existing - // caches in the eeprom to see if we have already cached something - // Or if no matches are found we will copy this into the header - eepromRecordHeader l_eepromRecord = {l_i2cMasterTarget->getAttr<TARGETING::ATTR_HUID>(), - (uint8_t)l_eepromInfo.port, - (uint8_t)l_eepromInfo.engine, - (uint8_t)l_eepromInfo.devAddr, - l_muxTarget->getAttr<TARGETING::ATTR_HUID>(), - l_eepromInfo.i2cMuxBusSelector, - (uint8_t)l_eepromInfo.devSize_KB, - 0, // Default internal offset to be 0 - i_present}; - size_t l_eepromLen = l_eepromInfo.devSize_KB * KILOBYTE; // Parse through PNOR section header to determine if a copy of this // eeprom already exists, or if we need to add it, and where we should add it // if we need to. - eepromRecordHeader * l_recordHeaderToUpdate; + eepromRecordHeader * l_recordHeaderToUpdate = nullptr; // Initialize this to an INVALID value. This way we catch the case where // cache has 50 records and we cannot add anymore. In that case l_recordHeaderToUpdateIndex @@ -279,77 +329,132 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target, // Keep track of current record so we can use outside for loop l_recordHeaderToUpdate = &l_eecacheSectionHeaderPtr->recordHeaders[i]; - // If internal_offset is non-zero then we will assume this address has been filled - if(l_recordHeaderToUpdate->internal_offset != UNSET_INTERNAL_OFFSET_VALUE) + + // If internal_offset is UNSET_INTERNAL_OFFSET_VALUE then we will assume this address not been filled + if(l_recordHeaderToUpdate->completeRecord.internal_offset == UNSET_INTERNAL_OFFSET_VALUE) + { + assert((l_eecacheSectionHeaderPtr->end_of_cache + l_eepromLen) < g_eecachePnorSize, + "Sum of system EEPROMs is larger than space allocated for EECACHE pnor section"); + + l_recordHeaderToUpdateIndex = i; + // Set this new eepromRecord's offset within the EECACHE PNOR section + // to be the current "end of cache" offset in the toc. + l_eepromRecordHeader.completeRecord.internal_offset = l_eecacheSectionHeaderPtr->end_of_cache; + l_eecacheSectionHeaderPtr->end_of_cache += l_eepromLen; + l_updateContents = i_present; + break; + } + + // Compare the eeprom record we are checking against the eeprom records we are iterating through + // but ignore the last 9 bytes which have chip size, the offset into this pnor section where the + // record exists, and a byte that tells us if its valid or not + if( memcmp(l_recordHeaderToUpdate, &l_eepromRecordHeader, NUM_BYTE_UNIQUE_ID ) == 0 ) { - // Compare the eeprom record we are checking against the eeprom records we are iterating through - // but ignore the last 9 bytes which have chip size, the offset into this pnor section where the - // record exists, and a byte that tells us if its valid or not - if( memcmp(l_recordHeaderToUpdate, &l_eepromRecord, RECORD_COMPARE_SIZE ) == 0 ) + l_recordHeaderToUpdateIndex = i; + + if( l_recordHeaderToUpdate->completeRecord.cache_copy_size != l_eepromRecordHeader.completeRecord.cache_copy_size) { - l_recordHeaderToUpdateIndex = i; - if( l_recordHeaderToUpdate->record_size != l_eepromRecord.record_size) + // This indicates that a part size has changed , caching + // algorithm cannot account for size changes. + // Invalidate entire cache and TI to trigger re-ipl + l_errl = PNOR::clearSection(PNOR::EECACHE); + + // If there was an error clearing the cache commit is because we are TIing + if(l_errl) { - // This indicates that a part size has changed , caching - // algorithm cannot account for size changes. - // Invalidate entire cache and TI to trigger re-ipl - l_errl = clearEEcache(); - - // If there was an error clearing the cache commit is because we are TIing - if(l_errl) - { - errlCommit(l_errl, I2C_COMP_ID); - } - - INITSERVICE::doShutdown(INITSERVICE::SHUTDOWN_DO_RECONFIG_LOOP); + errlCommit(l_errl, EEPROM_COMP_ID); } - if(l_recordHeaderToUpdate->record_valid) + /*@ + * @errortype ERRORLOG::ERRL_SEV_PREDICTIVE + * @moduleid EEPROM_CACHE_EEPROM + * @reasoncode EEPROM_NEW_DEVICE_DETECTED + * @userdata1[0:31] Old Size of Eeprom + * @userdata1[32:63] New Size of Eeprom + * @userdata2[0:31] HUID of I2C Master + * @userdata2[32:39] Port + * @userdata2[40:47] Engine + * @userdata2[48:55] HUID of I2C Master + * @userdata2[56:63] HUID of I2C Master + * @devdesc New part has likely been loaded into the system. + * @custdesc Firmware detected new part and is restarting + */ + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_PREDICTIVE, + EEPROM_CACHE_EEPROM, + EEPROM_NEW_DEVICE_DETECTED, + TWO_UINT32_TO_UINT64(l_recordHeaderToUpdate->completeRecord.cache_copy_size , + l_eepromRecordHeader.completeRecord.cache_copy_size), + TWO_UINT32_TO_UINT64(l_eepromRecordHeader.completeRecord.i2c_master_huid, + TWO_UINT16_TO_UINT32( + TWO_UINT8_TO_UINT16(l_eepromRecordHeader.completeRecord.port, + l_eepromRecordHeader.completeRecord.engine), + TWO_UINT8_TO_UINT16(l_eepromRecordHeader.completeRecord.devAddr, + l_eepromRecordHeader.completeRecord.mux_select)))); + errlCommit(l_errl, EEPROM_COMP_ID); + + #ifdef CONFIG_CONSOLE + CONSOLE::displayf(EEPROM_COMP_NAME, + "New EEPROM size detected for an existing part, clearing EEPROM cache and performing reconfig loop"); + #endif + + INITSERVICE::doShutdown(INITSERVICE::SHUTDOWN_DO_RECONFIG_LOOP); + } + + // + // At this point we have found a match in the PNOR but we need + // to decide what all needs an update + // + + // Stash the internal_offset of the section we found in so we can add + // this record to g_cachedEeproms for later use + l_eepromRecordHeader.completeRecord.internal_offset = + l_recordHeaderToUpdate->completeRecord.internal_offset; + + + if(l_recordHeaderToUpdate->completeRecord.cached_copy_valid) + { + // If the existing eeprom record is valid, then only update the + // contents if the SN/PN for current HW do not match the eeprom + // record. (target must be present to cache) + + // TODO RTC:203788 add lookup for PN and SN matches + //if( !i_present || PNandSNMatch ) { - // If the existing eeprom record is valid, then only update the - // contents if the SN/PN for current HW do not match the eeprom - // record. (target must be present to cache) - - // TODO RTC:203788 add lookup for PN and SN matches - //if( !i_present || PNandSNMatch ) - { - l_updateContents = false; - } - - // If target is present there is nothing in the - // header to update - if( i_present ) - { - l_updateHeader = false; - } + l_updateContents = false; } - else if(!i_present) + + // If target is present there is nothing in the + // header to update + if( i_present ) { - // If the target is not present, then do not update contents or header - l_updateContents = false; l_updateHeader = false; } - - TRACSSCOMP( g_trac_i2c, "cacheEeprom() already found copy for eeprom role %d for target w/ HUID 0x.%08X", - i_eepromType , TARGETING::get_huid(i_target)); - break; } - } - else - { - assert((l_eecacheSectionHeaderPtr->end_of_cache + l_eepromLen) < g_eecachePnorSize, - "Sum of system EEPROMs is larger than space allocated for EECACHE pnor section"); + else if(!i_present) + { + // If the target is not present, then do not update contents or header + l_updateContents = false; + l_updateHeader = false; + } - l_recordHeaderToUpdateIndex = i; - // Set this new eepromRecord's offset within the EECACHE PNOR section - // to be the current "end of cache" offset in the toc. - l_eepromRecord.internal_offset = l_eecacheSectionHeaderPtr->end_of_cache; - l_eecacheSectionHeaderPtr->end_of_cache += l_eepromLen; - l_updateContents = i_present; + TRACSSCOMP( g_trac_eeprom, "cacheEeprom() already found copy for eeprom role %d for target w/ HUID 0x.%08X", + i_eepromType , TARGETING::get_huid(i_target)); break; } } + if(!addEepromToCachedList(l_eepromRecordHeader)) + { + TRACSSCOMP( g_trac_eeprom, "cacheEeprom() Eeprom w/ Role %d, HUID 0x.%08X added to cached list", + i_eepromType , TARGETING::get_huid(i_target)); + } + else + { + TRACSSCOMP( g_trac_eeprom, "cacheEeprom() Eeprom w/ Role %d, HUID 0x.%08X already in cached list", + i_eepromType , TARGETING::get_huid(i_target)); + } + // Above we have determined whether the contents of the eeprom at // hand need to have their contents updated. Only do the following @@ -364,22 +469,22 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target, l_tmpBuffer = malloc(l_eepromLen); void * l_internalSectionAddr = - reinterpret_cast<uint8_t *>(l_eecacheSectionHeaderPtr) + l_eepromRecord.internal_offset; + reinterpret_cast<uint8_t *>(l_eecacheSectionHeaderPtr) + l_eepromRecordHeader.completeRecord.internal_offset; - TRACSSCOMP( g_trac_i2c, "cacheEeprom() passing the following into deviceOp eeprom address : huid 0x%.08X length 0x%.08X" , - get_huid(i_target), l_eepromLen); + TRACSSCOMP( g_trac_eeprom, "cacheEeprom() passing the following into deviceOp eeprom address : huid 0x%.08X length 0x%.08X vaddr %p" , + get_huid(i_target), l_eepromLen, l_internalSectionAddr); // Copy vpd contents to cache l_errl = deviceOp(DeviceFW::READ, i_target, l_tmpBuffer, l_eepromLen, - DEVICE_EEPROM_ADDRESS(i_eepromType, 0)); + DEVICE_EEPROM_ADDRESS(i_eepromType, 0, VPD::SEEPROM)); // If an error occurred during the eeprom read then free the tmp buffer and break out if( l_errl) { - TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error occured reading from EEPROM type %d for HUID 0x%.08X!", + TRACFCOMP(g_trac_eeprom,ERR_MRK"cacheEeprom: Error occured reading from EEPROM type %d for HUID 0x%.08X!", i_eepromType,get_huid(i_target)); free(l_tmpBuffer); break; @@ -392,26 +497,26 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target, int rc = mm_remove_pages( FLUSH, l_internalSectionAddr, l_eepromLen ); if( rc ) { - TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush contents write to pnor! rc=%d",rc); + TRACFCOMP(g_trac_eeprom,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush contents write to pnor! rc=%d",rc); /*@ * @errortype - * @moduleid I2C_CACHE_EEPROM - * @reasoncode I2C_FAILED_TO_FLUSH_CONTENTS + * @moduleid EEPROM_CACHE_EEPROM + * @reasoncode EEPROM_FAILED_TO_FLUSH_CONTENTS * @userdata1 Requested Address * @userdata2 rc from mm_remove_pages * @devdesc cacheEeprom mm_remove_pages FLUSH failed */ l_errl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - I2C_CACHE_EEPROM, - I2C_FAILED_TO_FLUSH_CONTENTS, + EEPROM_CACHE_EEPROM, + EEPROM_FAILED_TO_FLUSH_CONTENTS, (uint64_t)l_internalSectionAddr, TO_UINT64(rc), ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); } else { - TRACSSCOMP( g_trac_i2c, "cacheEeprom() %.08X bytes of eeprom data related to %.08X have been written to %p" , + TRACSSCOMP( g_trac_eeprom, "cacheEeprom() %.08X bytes of eeprom data related to %.08X have been written to %p" , l_eepromLen, get_huid(i_target), l_internalSectionAddr); } @@ -430,27 +535,30 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target, // the eeprom's header entry if we were told to do so. if(l_updateHeader) { + TRACDBIN( g_trac_eeprom, "cacheEeprom: l_eecacheSectionHeaderPtr currently ", + l_eecacheSectionHeaderPtr, + sizeof(eecacheSectionHeader)); // Copy the local eepromRecord header struct with the info about the // new eeprom we want to add to the cache to the open slot we found - memcpy(l_recordHeaderToUpdate , &l_eepromRecord, sizeof(eepromRecordHeader)); + memcpy(l_recordHeaderToUpdate , &l_eepromRecordHeader, sizeof(eepromRecordHeader)); // Flush the page to make sure it gets to the PNOR int rc = mm_remove_pages( FLUSH, l_recordHeaderToUpdate, sizeof(eepromRecordHeader) ); if( rc ) { - TRACFCOMP(g_trac_i2c,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush header write to pnor, rc=%d",rc); + TRACFCOMP(g_trac_eeprom,ERR_MRK"cacheEeprom: Error from mm_remove_pages trying for flush header write to pnor, rc=%d",rc); /*@ * @errortype - * @moduleid I2C_CACHE_EEPROM - * @reasoncode I2C_FAILED_TO_FLUSH_HEADER + * @moduleid EEPROM_CACHE_EEPROM + * @reasoncode EEPROM_FAILED_TO_FLUSH_HEADER * @userdata1 Requested Address * @userdata2 rc from mm_remove_pages * @devdesc cacheEeprom mm_remove_pages FLUSH failed */ l_errl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - I2C_CACHE_EEPROM, - I2C_FAILED_TO_FLUSH_HEADER, + EEPROM_CACHE_EEPROM, + EEPROM_FAILED_TO_FLUSH_HEADER, (uint64_t)l_recordHeaderToUpdate, TO_UINT64(rc), ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); @@ -458,12 +566,10 @@ errlHndl_t cacheEeprom(TARGETING::Target* i_target, } } - TRACDBIN( g_trac_i2c, "cacheEeprom: l_eecacheSectionHeaderPtr currently ", - l_eecacheSectionHeaderPtr, - sizeof(eecacheSectionHeader)); + }while(0); - TRACSSCOMP( g_trac_i2c, "cacheEeprom() EXIT Target HUID 0x%.08X ", TARGETING::get_huid(i_target)); + TRACSSCOMP( g_trac_eeprom, "cacheEeprom() EXIT Target HUID 0x%.08X ", TARGETING::get_huid(i_target)); return l_errl; } @@ -498,9 +604,9 @@ errlHndl_t genericI2CEepromCache(DeviceFW::OperationType i_opType, bool l_present = (bool)va_arg(i_args,uint64_t); // second param is the type of EEPROM type we wish to cache (PRIMARY vs BACKUP etc) - EEPROM::eeprom_chip_types_t l_eepromType = (EEPROM::eeprom_chip_types_t)va_arg(i_args,uint64_t); + EEPROM::EEPROM_ROLE l_eepromType = (EEPROM::EEPROM_ROLE)va_arg(i_args,uint64_t); - TRACSSCOMP( g_trac_i2c, ENTER_MRK"genericI2CEepromCache() " + TRACSSCOMP( g_trac_eeprom, ENTER_MRK"genericI2CEepromCache() " "Target HUID 0x%.08X Enter", TARGETING::get_huid(i_target)); do{ @@ -508,7 +614,7 @@ errlHndl_t genericI2CEepromCache(DeviceFW::OperationType i_opType, l_errl = cacheEeprom(i_target, l_present, l_eepromType); if(l_errl) { - TRACFCOMP(g_trac_i2c, + TRACFCOMP(g_trac_eeprom, ERR_MRK"cacheEeprom: An error occured while attempting to cache eeprom for 0x%.08X", TARGETING::get_huid(i_target)); break; @@ -516,7 +622,7 @@ errlHndl_t genericI2CEepromCache(DeviceFW::OperationType i_opType, }while(0); - TRACSSCOMP( g_trac_i2c, EXIT_MRK"genericI2CEepromCache() " + TRACSSCOMP( g_trac_eeprom, EXIT_MRK"genericI2CEepromCache() " "Target HUID 0x%.08X EXIT", TARGETING::get_huid(i_target)); return l_errl; @@ -537,4 +643,164 @@ DEVICE_REGISTER_ROUTE( DeviceFW::READ, TARGETING::TYPE_DIMM, genericI2CEepromCache ); +#endif + +errlHndl_t eepromPerformOpCache(DeviceFW::OperationType i_opType, + TARGETING::Target * i_target, + void * io_buffer, + size_t i_buflen, + eeprom_addr_t &i_eepromInfo) +{ + errlHndl_t l_errl = nullptr; + eepromRecordHeader l_eepromRecordHeader; + + do{ + + TRACSSCOMP( g_trac_eeprom, ENTER_MRK"eepromPerformOpCache() " + "Target HUID 0x%.08X Enter", TARGETING::get_huid(i_target)); + + l_errl = buildEepromRecordHeader(i_target, i_eepromInfo, l_eepromRecordHeader); + + if(l_errl) + { + // buildEepromRecordHeader should have traced any relavent information if + // it was needed, just break out and pass the error along + break; + } + + uint64_t l_eepromCacheVaddr = lookupEepromAddr(l_eepromRecordHeader); + + // Ensure that a copy of the eeprom exists in our map of cached eeproms + if(l_eepromCacheVaddr) + { + TRACSSCOMP( g_trac_eeprom, "eepromPerformOpCache() " + "Performing %s on target 0x%.08X offset 0x%lx length 0x%x vaddr 0x%lx", + (i_opType == DeviceFW::READ) ? "READ" : "WRITE", + TARGETING::get_huid(i_target), + i_eepromInfo.offset, i_buflen, l_eepromCacheVaddr); + + // Make sure that offset + buflen are less than the total size of the eeprom + if(i_eepromInfo.offset + i_buflen > (l_eepromRecordHeader.completeRecord.cache_copy_size * KILOBYTE)) + { + TRACFCOMP(g_trac_eeprom, + ERR_MRK"eepromPerformOpCache: i_eepromInfo.offset + i_offset is greater than size of eeprom (0x%x KB)", + l_eepromRecordHeader.completeRecord.cache_copy_size); + /*@ + * @errortype + * @moduleid EEPROM_CACHE_PERFORM_OP + * @reasoncode EEPROM_OVERFLOW_ERROR + * @userdata1 Length of Operation + * @userdata2 Offset we are attempting to read/write + * @custdesc Soft error in Firmware + * @devdesc cacheEeprom invalid op type + */ + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_CACHE_PERFORM_OP, + EEPROM_OVERFLOW_ERROR, + TO_UINT64(i_buflen), + TO_UINT64(i_eepromInfo.offset), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_errl); + l_errl->collectTrace( EEPROM_COMP_NAME ); + + break; + } + + if(i_opType == DeviceFW::READ) + { + memcpy(io_buffer, reinterpret_cast<void *>(l_eepromCacheVaddr + i_eepromInfo.offset), i_buflen); + } + else if(i_opType == DeviceFW::WRITE) + { + memcpy(reinterpret_cast<void *>(l_eepromCacheVaddr + i_eepromInfo.offset), io_buffer, i_buflen); + + #ifndef __HOSTBOOT_RUNTIME + + // Perform flush to ensure pnor is updated + int rc = mm_remove_pages( FLUSH, + reinterpret_cast<void *>(l_eepromCacheVaddr + i_eepromInfo.offset), + i_buflen ); + if( rc ) + { + TRACFCOMP(g_trac_eeprom,ERR_MRK"eepromPerformOpCache: Error from mm_remove_pages trying for flush contents write to pnor! rc=%d",rc); + /*@ + * @errortype + * @moduleid EEPROM_CACHE_PERFORM_OP + * @reasoncode EEPROM_FAILED_TO_FLUSH_CONTENTS + * @userdata1 Requested Address + * @userdata2 rc from mm_remove_pages + * @devdesc cacheEeprom mm_remove_pages FLUSH failed + */ + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_CACHE_PERFORM_OP, + EEPROM_FAILED_TO_FLUSH_CONTENTS, + (l_eepromCacheVaddr + i_eepromInfo.offset), + TO_UINT64(rc), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + l_errl->collectTrace( EEPROM_COMP_NAME ); + } + #endif //__HOSTBOOT_RUNTIME + } + else + { + TRACFCOMP(g_trac_eeprom,ERR_MRK"eepromPerformOpCache: Invalid OP_TYPE passed to function, i_opType=%d", i_opType); + /*@ + * @errortype + * @moduleid EEPROM_CACHE_PERFORM_OP + * @reasoncode EEPROM_INVALID_OPERATION + * @userdata1[0:31] Op Type that was invalid + * @userdata1[32:63] Eeprom Role + * @userdata2 Offset we are attempting to perfrom op on + * @custdesc Soft error in Firmware + * @devdesc cacheEeprom invalid op type + */ + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_CACHE_PERFORM_OP, + EEPROM_INVALID_OPERATION, + TWO_UINT32_TO_UINT64(i_opType, + i_eepromInfo.eepromRole), + TO_UINT64(i_eepromInfo.offset), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_errl); + l_errl->collectTrace( EEPROM_COMP_NAME ); + } + } + else + { + TRACFCOMP( g_trac_eeprom,"eepromPerformOpCache: Failed to find entry in cache for 0x%.08X, %s failed", + TARGETING::get_huid(i_target), + (i_opType == DeviceFW::READ) ? "READ" : "WRITE"); + /*@ + * @errortype + * @moduleid EEPROM_CACHE_PERFORM_OP + * @reasoncode EEPROM_NOT_IN_CACHE + * @userdata1[0:31] Op Type + * @userdata1[32:63] Eeprom Role + * @userdata2 Offset we are attempting to read/write + * @custdesc Soft error in Firmware + * @devdesc Tried to lookup eeprom not in cache + */ + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_CACHE_PERFORM_OP, + EEPROM_NOT_IN_CACHE, + TWO_UINT32_TO_UINT64(i_opType, + i_eepromInfo.eepromRole), + TO_UINT64(i_eepromInfo.offset), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_errl); + l_errl->collectTrace( EEPROM_COMP_NAME ); + } + + TRACSSCOMP( g_trac_eeprom, EXIT_MRK"eepromPerformOpCache() " + "Target HUID 0x%.08X Exit", TARGETING::get_huid(i_target)); + + }while(0); + + return l_errl; +} + }
\ No newline at end of file diff --git a/src/usr/i2c/eepromCache.H b/src/usr/i2c/eepromCache.H new file mode 100644 index 000000000..0e0be7368 --- /dev/null +++ b/src/usr/i2c/eepromCache.H @@ -0,0 +1,115 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/i2c/eepromCache.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2019 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __EEPROM_CACHE_H +#define __EEPROM_CACHE_H + +#include <i2c/eeprom_const.H> +#include <errl/errlentry.H> + +namespace EEPROM +{ + +/** +* +* @brief Perform a read or write operation on an eeprom record inside EEACHE +* +* +* @param[in] i_opType - Operation Type - See DeviceFW::OperationType in +* driververif.H +* +* @param[in] i_target - Target device associated w/ the EEPROM. +* +* @param[in/out] io_buffer +* INPUT: Pointer to the data that will be written to the target +* device. +* OUTPUT: Pointer to the data that was read from the target device. +* +* @param[in] i_buflen +* INPUT: Length of the buffer to be written to target device or +* length of buffer to be read from target device. +* +* @param [in] i_eepromInfo struct containing information needed to perform +* operation on the given i2c eeprom. NOTE It is expected that +* eepromRole and offset have been filled out in this struct +* prior to passing it into this function +* +* @return errlHndl_t - nullptr if successful, otherwise a pointer to the +* error log. +* +*/ +errlHndl_t eepromPerformOpCache(DeviceFW::OperationType i_opType, + TARGETING::Target * i_target, + void * io_buffer, + size_t i_buflen, + eeprom_addr_t &i_eepromInfo); + +/** +* +* @brief Build up a struct that is used to compare cached eeprom entries +* in the EECACHE section. Each eeprom will get an entry in the +* eepromRecordHeader order in the EECACHE section header +* +* @param[in] i_target - Target device associated w/ the EEPROM. +* +* @param [in/out] io_eepromInfo struct containing information needed to perform +* operation on the given i2c eeprom. NOTE It is expected that +* eepromRole has been filled out in this struct prior to passing +* it into this function +* @param [out] o_eepromRecordHeader struct that will be populated with infromation +* that can be used to determine if the eeprom has been cached yet or not, +* or for looking up an eeprom we want to write to/ read from. +* +* @pre It is expected that io_i2cInfo.eepromRole will have a valid role set +* +* @post After function o_eepromRecordHeader will be filled in with information +* found while looking up the eeprom info from the target's attributes. +* o_eepromRecordHeader can be used to see if a cached copy exists +* +* @return errlHndl_t - nullptr if successful, otherwise a pointer to the +* error log. +* +*/ +errlHndl_t buildEepromRecordHeader(TARGETING::Target * i_target, + eeprom_addr_t & io_eepromInfo, + eepromRecordHeader & o_eepromRecordHeader); + +/** +* +* @brief Perform a lookup on the global map g_cachedEeproms to get a +* virtual address for a given EEPROM +* +* @param[in] i_eepromRecordHeader +* +* @pre It is expected that i_eepromRecordHeader has valid information for +* the uniqueID (i2cm_huid, port, engine, devAddr, mux_select) +* +* @return uint64_t virtual address pointing to the cached eeprom data in pnor +* +*/ +uint64_t lookupEepromAddr(const eepromRecordHeader & i_eepromRecordHeader); + +} + +#endif
\ No newline at end of file diff --git a/src/usr/i2c/eeprom_utils.C b/src/usr/i2c/eeprom_utils.C new file mode 100644 index 000000000..806a0cf31 --- /dev/null +++ b/src/usr/i2c/eeprom_utils.C @@ -0,0 +1,800 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/i2c/eeprom_utils.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2019 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include <i2c/eepromif.H> +#include <i2c/i2cif.H> +#include <errl/errlmanager.H> +#include <errl/errludstring.H> +#include <i2c/eepromddreasoncodes.H> +#include <i2c/eeprom_const.H> +#include "i2c_common.H" + + +// ---------------------------------------------- +// Trace definitions +// ---------------------------------------------- +trace_desc_t* g_trac_eeprom = NULL; +TRAC_INIT( & g_trac_eeprom, EEPROM_COMP_NAME, KILOBYTE ); + +// Easy macro replace for unit testing +//#define TRACUCOMP(args...) TRACFCOMP(args) +#define TRACUCOMP(args...) + +namespace EEPROM +{ + +#ifndef __HOSTBOOT_RUNTIME +//------------------------------------------------------------------- +//eepromPresence +//------------------------------------------------------------------- +bool eepromPresence ( TARGETING::Target * i_target ) +{ + TRACUCOMP(g_trac_eeprom, ENTER_MRK"eepromPresence()"); + + errlHndl_t err = NULL; + bool l_present = false; + TARGETING::Target * i2cMasterTarget = NULL; + + eeprom_addr_t i2cInfo; + + i2cInfo.eepromRole = EEPROM::VPD_PRIMARY; + i2cInfo.offset = 0; + do + { + + // Read Attributes needed to complete the operation + err = eepromReadAttributes( i_target, + i2cInfo ); + + if( err ) + { + TRACFCOMP(g_trac_eeprom, + ERR_MRK"Error in eepromPresence::eepromReadAttributes()"); + break; + } + + // Check to see if we need to find a new target for + // the I2C Master + err = eepromGetI2CMasterTarget( i_target, + i2cInfo, + i2cMasterTarget ); + + if( err ) + { + TRACFCOMP(g_trac_eeprom, + ERR_MRK"Error in eepromPresence::eepromGetI2Cmaster()"); + break; + } + + //Check for the target at the I2C level + l_present = I2C::i2cPresence(i2cMasterTarget, + i2cInfo.port, + i2cInfo.engine, + i2cInfo.devAddr, + i2cInfo.i2cMuxBusSelector, + i2cInfo.i2cMuxPath); + + if( !l_present ) + { + TRACDCOMP(g_trac_eeprom, + ERR_MRK"i2cPresence returned false! chip NOT present!"); + break; + } + + } while( 0 ); + + // If there was an error commit the error log + if( err ) + { + errlCommit( err, I2C_COMP_ID ); + } + + TRACDCOMP(g_trac_eeprom, EXIT_MRK"eepromPresence()"); + return l_present; +} +#endif // __HOSTBOOT_RUNTIME + +/** + * + * @brief A useful utility to dump (trace out) the EepromVpdPrimaryInfo data. + * Use as needed. + * + * @param [in] i_i2cInfo - The EepromVpdPrimaryInfo data to dump for user + * + */ +void dumpEepromData(const TARGETING::EepromVpdPrimaryInfo & i_i2cInfo) +{ + TRACFCOMP (g_trac_eeprom, INFO_MRK"EepromVpdPrimaryInfo data: " + "engine=%d, port=%d, devAddr=0X%X, writePageSize=%d, " + "maxMemorySizeKB=0x%X, chipCount=%d, writeCycleTime=%d", + i_i2cInfo.engine, i_i2cInfo.port, i_i2cInfo.devAddr, + i_i2cInfo.writePageSize, i_i2cInfo.maxMemorySizeKB, + i_i2cInfo.chipCount, i_i2cInfo.writeCycleTime); + + char* l_masterPath = i_i2cInfo.i2cMasterPath.toString(); + char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); + TRACFCOMP (g_trac_eeprom, INFO_MRK"EepromVpdPrimaryInfo data cont.: " + "masterPath=%s, muxSelector=0x%X, muxPath=%s", + l_masterPath, i_i2cInfo.i2cMuxBusSelector, l_muxPath); + + free(l_masterPath); + free(l_muxPath); + l_masterPath = l_muxPath = nullptr; +} + + +/** + * + * @brief A useful utility to dump (trace out) the eeprom_addr_t data. + * Use as needed. + * + * @param [in] i_i2cInfo - The eeprom_addr_t data to dump for user + * + */ +void dumpEepromData(const eeprom_addr_t & i_i2cInfo) +{ + TRACFCOMP (g_trac_eeprom, INFO_MRK"eeprom_addr_t data: \n" + "engine=%d, port=%d, devAddr=0X%X, writePageSize=%d, \n" + "devSize_KB=0x%X, chipCount=%d, writeCycleTime=%d \n", + i_i2cInfo.engine, i_i2cInfo.port, i_i2cInfo.devAddr, + i_i2cInfo.writePageSize, i_i2cInfo.devSize_KB, + i_i2cInfo.chipCount, i_i2cInfo.writeCycleTime); + + char* l_masterPath = i_i2cInfo.i2cMasterPath.toString(); + char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); + TRACFCOMP (g_trac_eeprom, INFO_MRK"eeprom_addr_t data cont.: \n" + "masterPath=%s, muxSelector=0x%X, muxPath=%s \n", + l_masterPath, i_i2cInfo.i2cMuxBusSelector, l_muxPath); + + free(l_masterPath); + free(l_muxPath); + l_masterPath = l_muxPath = nullptr; +} + + +// ------------------------------------------------------------------ +// eepromReadAttributes +// ------------------------------------------------------------------ +errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target, + eeprom_addr_t & o_i2cInfo ) +{ + errlHndl_t err = NULL; + bool fail_reading_attribute = false; + + TRACDCOMP( g_trac_eeprom, + ENTER_MRK"eepromReadAttributes()" ); + + // This variable will be used to hold the EEPROM attribute data + // Note: each 'EepromVpd' struct is kept the same via the attributes + // so will be copying each to eepromData to save code space + TARGETING::EepromVpdPrimaryInfo eepromData; + + do + { + + switch (o_i2cInfo.eepromRole ) + { + case VPD_PRIMARY: + if( !( i_target-> + tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO> + ( eepromData ) ) ) + + { + fail_reading_attribute = true; + } + break; + + case VPD_BACKUP: + + if( !(i_target-> + tryGetAttr<TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO> + ( reinterpret_cast< + TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO_type&> + ( eepromData) ) ) ) + { + fail_reading_attribute = true; + } + break; + + case SBE_PRIMARY: + if( !(i_target-> + tryGetAttr<TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO> + ( reinterpret_cast< + TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO_type&> + ( eepromData) ) ) ) + { + fail_reading_attribute = true; + } + break; + + case SBE_BACKUP: + if( (!i_target-> + tryGetAttr<TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO> + ( reinterpret_cast< + TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO_type&> + ( eepromData) ) ) ) + { + fail_reading_attribute = true; + } + break; + + default: + TRACFCOMP( g_trac_eeprom,ERR_MRK"eepromReadAttributes() - " + "Invalid chip (%d) to read attributes from!", + o_i2cInfo.eepromRole ); + + /*@ + * @errortype + * @reasoncode EEPROM_INVALID_CHIP + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid EEPROM_READATTRIBUTES + * @userdata1 EEPROM Chip + * @userdata2 HUID of target + * @devdesc Invalid EEPROM chip to access + */ + err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_READATTRIBUTES, + EEPROM_INVALID_CHIP, + o_i2cInfo.eepromRole, + TARGETING::get_huid(i_target), + true /*Add HB SW Callout*/ ); + + err->collectTrace( EEPROM_COMP_NAME ); + + break; + } + + // Check if Attribute Data was found + if( fail_reading_attribute == true ) + { + TRACFCOMP( g_trac_eeprom, + ERR_MRK"eepromReadAttributes() - ERROR reading " + "attributes for eeprom role %d!", + o_i2cInfo.eepromRole ); + + /*@ + * @errortype + * @reasoncode EEPROM_ATTR_INFO_NOT_FOUND + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid EEPROM_READATTRIBUTES + * @userdata1 HUID of target + * @userdata2 EEPROM chip + * @devdesc EEPROM attribute was not found + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_READATTRIBUTES, + EEPROM_ATTR_INFO_NOT_FOUND, + TARGETING::get_huid(i_target), + o_i2cInfo.eepromRole); + + // Could be FSP or HB code's fault + err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, + HWAS::SRCI_PRIORITY_MED); + err->addProcedureCallout(HWAS::EPUB_PRC_SP_CODE, + HWAS::SRCI_PRIORITY_MED); + + err->collectTrace( EEPROM_COMP_NAME ); + + break; + + } + + // Successful reading of Attribute, so extract the data + o_i2cInfo.port = eepromData.port; + o_i2cInfo.devAddr = eepromData.devAddr; + o_i2cInfo.engine = eepromData.engine; + o_i2cInfo.i2cMasterPath = eepromData.i2cMasterPath; + o_i2cInfo.writePageSize = eepromData.writePageSize; + o_i2cInfo.devSize_KB = eepromData.maxMemorySizeKB; + o_i2cInfo.chipCount = eepromData.chipCount; + o_i2cInfo.writeCycleTime = eepromData.writeCycleTime; + o_i2cInfo.i2cMuxBusSelector = eepromData.i2cMuxBusSelector; + o_i2cInfo.i2cMuxPath = eepromData.i2cMuxPath; + + // Convert attribute info to eeprom_addr_size_t enum + if ( eepromData.byteAddrOffset == 0x3 ) + { + o_i2cInfo.addrSize = ONE_BYTE_ADDR; + } + else if ( eepromData.byteAddrOffset == 0x2 ) + { + o_i2cInfo.addrSize = TWO_BYTE_ADDR; + } + else if ( eepromData.byteAddrOffset == 0x1 ) + { + o_i2cInfo.addrSize = ONE_BYTE_ADDR_PAGESELECT; + } + else if ( eepromData.byteAddrOffset == 0x0 ) + { + o_i2cInfo.addrSize = ZERO_BYTE_ADDR; + } + else + { + TRACFCOMP( g_trac_eeprom, + ERR_MRK"eepromReadAttributes() - INVALID ADDRESS " + "OFFSET SIZE %d!", + o_i2cInfo.addrSize ); + + /*@ + * @errortype + * @reasoncode EEPROM_INVALID_ADDR_OFFSET_SIZE + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid EEPROM_READATTRIBUTES + * @userdata1 HUID of target + * @userdata2 Address Offset Size + * @devdesc Invalid address offset size + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_READATTRIBUTES, + EEPROM_INVALID_ADDR_OFFSET_SIZE, + TARGETING::get_huid(i_target), + o_i2cInfo.addrSize, + true /*Add HB SW Callout*/ ); + + err->collectTrace( EEPROM_COMP_NAME ); + + break; + + } + + } while( 0 ); + + TRACUCOMP(g_trac_eeprom,"eepromReadAttributes() tgt=0x%X, %d/%d/0x%X " + "dsKb=0x%X, aS=%d (%d)", + TARGETING::get_huid(i_target), + o_i2cInfo.port, o_i2cInfo.engine, o_i2cInfo.devAddr, + o_i2cInfo.devSize_KB, o_i2cInfo.addrSize, + eepromData.byteAddrOffset); + + + + // Printing mux info separately, if combined, nothing is displayed + char* l_muxPath = o_i2cInfo.i2cMuxPath.toString(); + TRACFCOMP(g_trac_eeprom, "eepromReadAttributes(): " + "muxSelector=0x%X, muxPath=%s", + o_i2cInfo.i2cMuxBusSelector, + l_muxPath); + free(l_muxPath); + l_muxPath = nullptr; + + TRACDCOMP( g_trac_eeprom, + EXIT_MRK"eepromReadAttributes()" ); + + return err; +} // end eepromReadAttributes + + +// ------------------------------------------------------------------ +// eepromGetI2CMasterTarget +// ------------------------------------------------------------------ +errlHndl_t eepromGetI2CMasterTarget ( TARGETING::Target * i_target, + const eeprom_addr_t & i_i2cInfo, + TARGETING::Target * &o_target ) +{ + errlHndl_t err = NULL; + o_target = NULL; + + TRACDCOMP( g_trac_eeprom, + ENTER_MRK"eepromGetI2CMasterTarget()" ); + + do + { + TARGETING::TargetService& tS = TARGETING::targetService(); + + // The path from i_target to its I2C Master was read from the + // attribute via eepromReadAttributes() and passed to this function + // in i_i2cInfo.i2cMasterPath + + // check that the path exists + bool exists = false; + tS.exists( i_i2cInfo.i2cMasterPath, + exists ); + + if( !exists ) + { + TRACFCOMP( g_trac_eeprom, + ERR_MRK"eepromGetI2CMasterTarget() - " + "i2cMasterPath attribute path doesn't exist!" ); + + // Compress the entity path + uint64_t l_epCompressed = 0; + for( uint32_t i = 0; i < i_i2cInfo.i2cMasterPath.size(); i++ ) + { + // Can only fit 4 path elements into 64 bits + if ( i <= 3 ) + { + // Path element: type:8 instance:8 + l_epCompressed |= + i_i2cInfo.i2cMasterPath[i].type << (16*(3-i)); + l_epCompressed |= + i_i2cInfo.i2cMasterPath[i].instance << ((16*(3-i))-8); + } + + // Always trace all of the info even if we cannot fit it in error log + TRACFCOMP( g_trac_eeprom, + ERR_MRK"eepromGetI2CMasterTarget() - " + "i_i2cInfo.i2cMasterPath[%d].type = %.02X i_i2cInfo.i2cMasterPath[%d].instance = %.02X", + i, i_i2cInfo.i2cMasterPath[i].type, i, i_i2cInfo.i2cMasterPath[i].instance ); + + } + + /*@ + * @errortype + * @reasoncode EEPROM_I2C_MASTER_PATH_ERROR + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid EEPROM_GETI2CMASTERTARGET + * @userdata1[00:31] Attribute Chip Type Enum + * @userdata1[32:63] HUID of target + * @userdata2 Compressed Entity Path + * @devdesc I2C master entity path doesn't exist. + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_GETI2CMASTERTARGET, + EEPROM_I2C_MASTER_PATH_ERROR, + TWO_UINT32_TO_UINT64( + i_i2cInfo.eepromRole, + TARGETING::get_huid(i_target) ), + l_epCompressed, + true /*Add HB SW Callout*/ ); + + err->collectTrace( EEPROM_COMP_NAME ); + + char* l_masterPath = i_i2cInfo.i2cMasterPath.toString(); + ERRORLOG::ErrlUserDetailsString(l_masterPath).addToLog(err); + free(l_masterPath); + l_masterPath = nullptr; + + break; + } + + // Since it exists, convert to a target + o_target = tS.toTarget( i_i2cInfo.i2cMasterPath ); + + if( NULL == o_target ) + { + TRACFCOMP( g_trac_eeprom, + ERR_MRK"eepromGetI2CMasterTarget() - I2C Master " + "Path target was NULL!" ); + + // Compress the entity path + uint64_t l_epCompressed = 0; + for( uint32_t i = 0; i < i_i2cInfo.i2cMasterPath.size(); i++ ) + { + // Can only fit 4 path elements into 64 bits + if ( i <= 3 ) + { + // Path element: type:8 instance:8 + l_epCompressed |= + i_i2cInfo.i2cMasterPath[i].type << (16*(3-i)); + l_epCompressed |= + i_i2cInfo.i2cMasterPath[i].instance << ((16*(3-i))-8); + } + + // Always trace all of the info even if we cannot fit it in error log + TRACFCOMP( g_trac_eeprom, + ERR_MRK"eepromGetI2CMasterTarget() - " + "i_i2cInfo.i2cMasterPath[%d].type = %.02X i_i2cInfo.i2cMasterPath[%d].instance = %.02X", + i, i_i2cInfo.i2cMasterPath[i].type, i, i_i2cInfo.i2cMasterPath[i].instance ); + + } + + /*@ + * @errortype + * @reasoncode EEPROM_TARGET_NULL + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid EEPROM_GETI2CMASTERTARGET + * @userdata1[00:31] Attribute Chip Type Enum + * @userdata1[32:63] HUID of target + * @userdata2 Compressed Entity Path + * @devdesc I2C master path target is null. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_GETI2CMASTERTARGET, + EEPROM_TARGET_NULL, + TWO_UINT32_TO_UINT64( + i_i2cInfo.eepromRole, + TARGETING::get_huid(i_target) ), + l_epCompressed, + true /*Add HB SW Callout*/ ); + + err->collectTrace( EEPROM_COMP_NAME ); + + char* l_masterPath = i_i2cInfo.i2cMasterPath.toString(); + ERRORLOG::ErrlUserDetailsString(l_masterPath).addToLog(err); + free(l_masterPath); + l_masterPath = nullptr; + + break; + } + + } while( 0 ); + + TRACDCOMP( g_trac_eeprom, + EXIT_MRK"eepromGetI2CMasterTarget()" ); + + return err; +} // end eepromGetI2CMasterTarget + + +/** + * @brief Compare predicate for EepromInfo_t + */ +class isSameEeprom +{ + public: + isSameEeprom( const EepromInfo_t& i_first ) + : iv_first(i_first) + {} + + bool operator()( const EepromInfo_t& i_second ) + { + return( (iv_first.i2cMaster == i_second.i2cMaster) + && (iv_first.engine == i_second.engine) + && (iv_first.port == i_second.port) + && (iv_first.devAddr == i_second.devAddr) ); + } + private: + const EepromInfo_t& iv_first; +}; + +/** + * @brief Add any new EEPROMs associated with this target + * to the list + * @param[in] i_list : list of previously discovered EEPROMs + * @param[out] i_targ : owner of EEPROMs to add + */ +void add_to_list( std::list<EepromInfo_t>& i_list, + TARGETING::Target* i_targ ) +{ + TRACFCOMP(g_trac_eeprom,"Targ %.8X",TARGETING::get_huid(i_targ)); + + // try all defined types of EEPROMs + for( EEPROM_ROLE eep_type = FIRST_CHIP_TYPE; + eep_type < LAST_CHIP_TYPE; + eep_type = static_cast<EEPROM_ROLE>(eep_type+1) ) + { + bool found_eep = false; + TARGETING::EepromVpdPrimaryInfo eepromData; + + switch( eep_type ) + { + case VPD_PRIMARY: + if( i_targ-> + tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO> + ( eepromData ) ) + + { + found_eep = true; + } + break; + + case VPD_BACKUP: + if( i_targ-> + tryGetAttr<TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO> + ( reinterpret_cast< + TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO_type&> + ( eepromData) ) ) + { + found_eep = true; + } + break; + + case SBE_PRIMARY: + if( i_targ-> + tryGetAttr<TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO> + ( reinterpret_cast< + TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO_type&> + ( eepromData) ) ) + { + found_eep = true; + } + break; + + case SBE_BACKUP: + if( i_targ-> + tryGetAttr<TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO> + ( reinterpret_cast< + TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO_type&> + ( eepromData) ) ) + { + found_eep = true; + } + break; + + case LAST_CHIP_TYPE: + //only included to catch additional types later on + found_eep = false; + break; + } + + if( !found_eep ) + { + TRACDCOMP(g_trac_eeprom,"eep_type=%d not found",eep_type); + //nothing to do + continue; + } + + // check that the path exists + bool exists = false; + TARGETING::targetService().exists( eepromData.i2cMasterPath, + exists ); + if( !exists ) + { + TRACDCOMP(g_trac_eeprom,"no master path"); + continue; + } + + // Since it exists, convert to a target + TARGETING::Target* i2cm = TARGETING::targetService() + .toTarget( eepromData.i2cMasterPath ); + if( NULL == i2cm ) + { + //not sure how this could happen, but just skip it + TRACDCOMP(g_trac_eeprom,"no target"); + continue; + } + + // ignore anything with junk data + TARGETING::Target * sys = NULL; + TARGETING::targetService().getTopLevelTarget( sys ); + if( i2cm == sys ) + { + TRACDCOMP(g_trac_eeprom,"sys target"); + continue; + } + + // copy all the data out + EepromInfo_t eep_info; + eep_info.i2cMaster = i2cm; + eep_info.engine = eepromData.engine; + eep_info.port = eepromData.port; + eep_info.devAddr = eepromData.devAddr; + eep_info.device = eep_type; + eep_info.assocTarg = i_targ; + eep_info.chipCount = eepromData.chipCount; + eep_info.sizeKB = eepromData.maxMemorySizeKB; + eep_info.addrBytes = eepromData.byteAddrOffset; + //one more lookup for the speed + TARGETING::ATTR_I2C_BUS_SPEED_ARRAY_type speeds; + if( i2cm->tryGetAttr<TARGETING::ATTR_I2C_BUS_SPEED_ARRAY> + (speeds) ) + { + if( (eep_info.engine > I2C_BUS_MAX_ENGINE(speeds)) + || (eep_info.port > I2C_BUS_MAX_PORT(speeds)) ) + { + TRACDCOMP(g_trac_eeprom,"bad engine/port"); + continue; + } + eep_info.busFreq = speeds[eep_info.engine][eep_info.port]; + eep_info.busFreq *= 1000; //convert KHz->Hz + } + else + { + TRACDCOMP(g_trac_eeprom,"eep_type=%d, Speed=0",eep_type); + continue; + } + + // check if the eeprom is already in our list + std::list<EepromInfo_t>::iterator oldeep = + find_if( i_list.begin(), i_list.end(), + isSameEeprom(eep_info) ); + if( oldeep == i_list.end() ) + { + // didn't find it in our list so stick it into the output list + i_list.push_back(eep_info); + TRACFCOMP(g_trac_eeprom,"--Adding i2cm=%.8X, type=%d, eng=%d, port=%d, addr=%.2X for %.8X", TARGETING::get_huid(i2cm),eep_type,eepromData.engine,eepromData.port, eep_info.devAddr, TARGETING::get_huid(eep_info.assocTarg)); + } + else + { + TRACFCOMP(g_trac_eeprom,"--Skipping duplicate i2cm=%.8X, type=%d, eng=%d, port=%d, addr=%.2X for %.8X", TARGETING::get_huid(i2cm),eep_type,eepromData.engine,eepromData.port, eep_info.devAddr, TARGETING::get_huid(eep_info.assocTarg)); + } + } +} + +/** + * @brief Return a set of information related to every unique + * EEPROM in the system + */ +void getEEPROMs( std::list<EepromInfo_t>& o_info ) +{ + TRACFCOMP(g_trac_eeprom,">>getEEPROMs()"); + + // We only want to have a single entry in our list per + // physical EEPROM. Since multiple targets could be + // using the same EEPROM, we need to have a hierarchy + // of importance. + // node/planar > proc > membuf > dimm + + // predicate to only look for this that are actually there + TARGETING::PredicateHwas isPresent; + isPresent.reset().poweredOn(true).present(true); + + // #1 - Nodes + TARGETING::PredicateCTM nodes( TARGETING::CLASS_ENC, + TARGETING::TYPE_NODE, + TARGETING::MODEL_NA ); + TARGETING::PredicatePostfixExpr l_nodeFilter; + l_nodeFilter.push(&isPresent).push(&nodes).And(); + TARGETING::TargetRangeFilter node_itr( TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_nodeFilter ); + for( ; node_itr; ++node_itr ) + { + add_to_list( o_info, *node_itr ); + } + + // #2 - Procs + TARGETING::PredicateCTM procs( TARGETING::CLASS_CHIP, + TARGETING::TYPE_PROC, + TARGETING::MODEL_NA ); + TARGETING::PredicatePostfixExpr l_procFilter; + l_procFilter.push(&isPresent).push(&procs).And(); + TARGETING::TargetRangeFilter proc_itr( TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_procFilter ); + for( ; proc_itr; ++proc_itr ) + { + add_to_list( o_info, *proc_itr ); + } + + // #3 - Membufs + TARGETING::PredicateCTM membs( TARGETING::CLASS_CHIP, + TARGETING::TYPE_MEMBUF, + TARGETING::MODEL_NA ); + TARGETING::PredicatePostfixExpr l_membFilter; + l_membFilter.push(&isPresent).push(&membs).And(); + TARGETING::TargetRangeFilter memb_itr( TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_membFilter ); + for( ; memb_itr; ++memb_itr ) + { + add_to_list( o_info, *memb_itr ); + } + + // #4 - DIMMs + TARGETING::PredicateCTM dimms( TARGETING::CLASS_LOGICAL_CARD, + TARGETING::TYPE_DIMM, + TARGETING::MODEL_NA ); + TARGETING::PredicatePostfixExpr l_dimmFilter; + l_dimmFilter.push(&isPresent).push(&dimms).And(); + TARGETING::TargetRangeFilter dimm_itr( TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_dimmFilter ); + for( ; dimm_itr; ++dimm_itr ) + { + #ifdef CONFIG_NVDIMM + // Skip if this is an NVDIMM as this will get added later + if (TARGETING::isNVDIMM( *dimm_itr )) + continue; + #endif + add_to_list( o_info, *dimm_itr ); + } + + TRACFCOMP(g_trac_eeprom,"<<getEEPROMs()"); +} + +}
\ No newline at end of file diff --git a/src/usr/i2c/eepromdd.C b/src/usr/i2c/eepromdd.C index c14180a3a..7e56aa6b7 100755 --- a/src/usr/i2c/eepromdd.C +++ b/src/usr/i2c/eepromdd.C @@ -35,164 +35,108 @@ // ---------------------------------------------- // Includes // ---------------------------------------------- -#include <string.h> -#include <sys/time.h> -#include <trace/interface.H> -#include <errl/errlentry.H> -#include <errl/errlmanager.H> -#include <errl/errludtarget.H> -#include <errl/errludstring.H> -#include <targeting/common/targetservice.H> -#include <targeting/common/util.H> -#include <devicefw/driverif.H> -#include <i2c/eepromddreasoncodes.H> -#include <i2c/eepromif.H> -#include <i2c/i2creasoncodes.H> -#include <i2c/i2cif.H> -#include "eepromdd.H" -#include "errlud_i2c.H" +#include <errl/errlentry.H> // errlHndl_t +#include <devicefw/driverif.H> // DeviceFW::OperationTyp + // TARGETING::Target + // va_list +#include "eepromCache.H" +#include "eepromdd_hardware.H" -// ---------------------------------------------- -// Globals -// ---------------------------------------------- -mutex_t g_eepromMutex = MUTEX_INITIALIZER; - -// ---------------------------------------------- -// Trace definitions -// ---------------------------------------------- -trace_desc_t* g_trac_eeprom = NULL; -TRAC_INIT( & g_trac_eeprom, EEPROM_COMP_NAME, KILOBYTE ); - -trace_desc_t* g_trac_eepromr = NULL; -TRAC_INIT( & g_trac_eepromr, "EEPROMR", KILOBYTE ); +extern trace_desc_t* g_trac_eeprom; // Easy macro replace for unit testing //#define TRACUCOMP(args...) TRACFCOMP(args) #define TRACUCOMP(args...) -// ---------------------------------------------- -// Defines -// ---------------------------------------------- -#define MAX_BYTE_ADDR 2 -#define EEPROM_MAX_RETRIES 2 -// ---------------------------------------------- - - -namespace -{ - -// ------------------------------------------------------------------ -// errorIsRetryable -// ------------------------------------------------------------------ -static bool errorIsRetryable(uint16_t reasonCode) -{ - return reasonCode == I2C::I2C_NACK_ONLY_FOUND || - reasonCode == I2C::I2C_ARBITRATION_LOST_ONLY_FOUND; -} - -} - namespace EEPROM { -// Register the perform Op with the routing code for Procs. -DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, - DeviceFW::EEPROM, - TARGETING::TYPE_PROC, - eepromPerformOp ); - -// Register the perform Op with the routing code for DIMMs. -DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, - DeviceFW::EEPROM, - TARGETING::TYPE_DIMM, - eepromPerformOp ); - -// Register the perform Op with the routing code for Memory Buffers. -DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, - DeviceFW::EEPROM, - TARGETING::TYPE_MEMBUF, - eepromPerformOp ); - -// Register the perform Op with the routing code for Nodes. -DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, - DeviceFW::EEPROM, - TARGETING::TYPE_NODE, - eepromPerformOp ); - -// Register the perform Op with the routing code for MCS chiplets. -DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, - DeviceFW::EEPROM, - TARGETING::TYPE_MCS, - eepromPerformOp ); - -// Register the perform Op with the routing code for Open-Capi Memory Buffer Chips. -DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, - DeviceFW::EEPROM, - TARGETING::TYPE_OCMB_CHIP, - eepromPerformOp ); - - -/** - * - * @brief A useful utility to dump (trace out) the EepromVpdPrimaryInfo data. - * Use as needed. - * - * @param [in] i_i2cInfo - The EepromVpdPrimaryInfo data to dump for user - * - */ -void dumpEepromData(const TARGETING::EepromVpdPrimaryInfo & i_i2cInfo) -{ - TRACFCOMP (g_trac_eeprom, INFO_MRK"EepromVpdPrimaryInfo data: " - "engine=%d, port=%d, devAddr=0X%X, writePageSize=%d, " - "maxMemorySizeKB=0x%X, chipCount=%d, writeCycleTime=%d", - i_i2cInfo.engine, i_i2cInfo.port, i_i2cInfo.devAddr, - i_i2cInfo.writePageSize, i_i2cInfo.maxMemorySizeKB, - i_i2cInfo.chipCount, i_i2cInfo.writeCycleTime); - - char* l_masterPath = i_i2cInfo.i2cMasterPath.toString(); - char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); - TRACFCOMP (g_trac_eeprom, INFO_MRK"EepromVpdPrimaryInfo data cont.: " - "masterPath=%s, muxSelector=0x%X, muxPath=%s", - l_masterPath, i_i2cInfo.i2cMuxBusSelector, l_muxPath); - - free(l_masterPath); - free(l_muxPath); - l_masterPath = l_muxPath = nullptr; -} - +#ifdef CONFIG_SUPPORT_EEPROM_CACHING /** - * - * @brief A useful utility to dump (trace out) the eeprom_addr_t data. - * Use as needed. - * - * @param [in] i_i2cInfo - The eeprom_addr_t data to dump for user - * - */ -void dumpEepromData(const eeprom_addr_t & i_i2cInfo) -{ - TRACFCOMP (g_trac_eeprom, INFO_MRK"eeprom_addr_t data: \n" - "engine=%d, port=%d, devAddr=0X%X, writePageSize=%d, \n" - "devSize_KB=0x%X, chipCount=%d, writeCycleTime=%d \n", - i_i2cInfo.engine, i_i2cInfo.port, i_i2cInfo.devAddr, - i_i2cInfo.writePageSize, i_i2cInfo.devSize_KB, - i_i2cInfo.chipCount, i_i2cInfo.writeCycleTime); - - char* l_masterPath = i_i2cInfo.i2cMasterPath.toString(); - char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); - TRACFCOMP (g_trac_eeprom, INFO_MRK"eeprom_addr_t data cont.: \n" - "masterPath=%s, muxSelector=0x%X, muxPath=%s \n", - l_masterPath, i_i2cInfo.i2cMuxBusSelector, l_muxPath); +* +* @brief Determine if a given EEPROM has been cached into pnor's EECACHE +* section yet or not. If it has source will be CACHE, if it has not +* been cached yet, then source will be HARDWARE +* +* +* @param[in] i_target - Target device associated with the eeprom. +* +* @param[in/out] io_i2cInfo - Struct containing information that tells us which +* EEPROM associated with the given Target we wish +* to lookup. NOTE it is assumed eepromRole member +* in this struct has been filled out prior to it +* being passed to this function. +* +* @pre i_i2cInfo.eepromRole is expected to have a valid value set +* +* @post o_source will either be EEPROM::CACHE or EEPROM::HARDWARE +* io_i2cInfo will have info filled out (side effect not used) +* +* @return errlHndl_t - NULL if successful, otherwise a pointer to the +* error log. +* +*/ +errlHndl_t resolveSource(TARGETING::Target * i_target, + eeprom_addr_t & io_i2cInfo, + EEPROM::EEPROM_SOURCE & o_source) +{ + eepromRecordHeader l_eepromRecordHeader; + errlHndl_t err = nullptr; + + err = buildEepromRecordHeader(i_target, + io_i2cInfo, + l_eepromRecordHeader); + // if lookupEepromAddr returns non-zero address + // then we know it exists in cache somewhere + if(lookupEepromAddr(l_eepromRecordHeader)) + { + o_source = EEPROM::CACHE; + } + else + { + o_source = EEPROM::HARDWARE; + } - free(l_masterPath); - free(l_muxPath); - l_masterPath = l_muxPath = nullptr; + return err; } +#endif // CONFIG_SUPPORT_EEPROM_CACHING // ------------------------------------------------------------------ // eepromPerformOp // ------------------------------------------------------------------ +/** +* +* @brief Perform an EEPROM access operation. +* +* @param[in] i_opType - Operation Type - See DeviceFW::OperationType in +* driververif.H +* +* @param[in] i_target - Target device. +* +* @param[in/out] io_buffer +* INPUT: Pointer to the data that will be written to the target +* device. +* OUTPUT: Pointer to the data that was read from the target device. +* +* @param[in/out] io_buflen +* INPUT: Length of the buffer to be written to target device. +* OUTPUT: Length of buffer that was written, or length of buffer +* to be read from target device. +* +* @param [in] i_accessType - Access Type - See DeviceFW::AccessType in +* usrif.H +* +* @param [in] i_args - This is an argument list for the device driver +* framework. This argument list consists of the chip number of +* the EEPROM to access from the given I2C Master target and the +* internal offset to use on the slave I2C device. +* +* @return errlHndl_t - NULL if successful, otherwise a pointer to the +* error log. +* +*/ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType, TARGETING::Target * i_target, void * io_buffer, @@ -200,2006 +144,109 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType, int64_t i_accessType, va_list i_args ) { - errlHndl_t err = NULL; - TARGETING::Target * i2cMasterTarget = NULL; + errlHndl_t err = nullptr; eeprom_addr_t i2cInfo; i2cInfo.eepromRole = va_arg( i_args, uint64_t ); - i2cInfo.offset = va_arg( i_args, uint64_t ); - + i2cInfo.offset = va_arg( i_args, uint64_t ); + #ifdef CONFIG_SUPPORT_EEPROM_CACHING + EEPROM_SOURCE l_source = (EEPROM_SOURCE)va_arg(i_args, uint64_t); + #endif TRACDCOMP( g_trac_eeprom, ENTER_MRK"eepromPerformOp()" ); TRACUCOMP (g_trac_eeprom, ENTER_MRK"eepromPerformOp(): " "i_opType=%d, chip=%d, offset=%x, len=%d", (uint64_t) i_opType, i2cInfo.eepromRole, i2cInfo.offset, io_buflen); + do{ -#ifdef __HOSTBOOT_RUNTIME - // At runtime the OCC sensor cache will need to be diabled to avoid I2C - // collisions. This bool indicates the sensor cache was enabled but is - // now disabled and needs to be re-enabled when the eeprom op completes. - bool scacDisabled = false; -#endif //__HOSTBOOT_RUNTIME - - void * l_pBuffer = io_buffer; - size_t l_currentOpLen = io_buflen; - size_t l_remainingOpLen = io_buflen; - - do - { - // Read Attributes needed to complete the operation - err = eepromReadAttributes( i_target, - i2cInfo ); - - if( err ) + #ifdef CONFIG_SUPPORT_EEPROM_CACHING + if(l_source == EEPROM::AUTOSELECT) { - break; + err = resolveSource(i_target, i2cInfo, l_source); } - size_t l_snglChipSize = (i2cInfo.devSize_KB * KILOBYTE) - / i2cInfo.chipCount; - - // Check to see if we need to find a new target for - // the I2C Master - err = eepromGetI2CMasterTarget( i_target, - i2cInfo, - i2cMasterTarget ); - - if( err ) - { - break; - } - - // Check that the offset + data length is less than device max size - if ( ( i2cInfo.offset + io_buflen ) > - ( i2cInfo.devSize_KB * KILOBYTE ) ) + if(err) { TRACFCOMP( g_trac_eeprom, - ERR_MRK"eepromPerformOp(): Device Overflow! " - "C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X " - "devSizeKB=0x%X", i2cInfo.eepromRole, i2cInfo.engine, - i2cInfo.port, i2cInfo.devAddr, i2cInfo.offset, - io_buflen, i2cInfo.devSize_KB); - - - /*@ - * @errortype - * @reasoncode EEPROM_OVERFLOW_ERROR - * @severity ERRL_SEV_UNRECOVERABLE - * @moduleid EEPROM_PERFORM_OP - * @userdata1[0:31] Offset - * @userdata1[32:63] Buffer Length - * @userdata2 Device Max Size (in KB) - * @devdesc I2C Buffer Length + Offset > Max Size - * @custdesc A problem occurred during the IPL of the - * system: I2C buffer offset is too large. - */ - err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - EEPROM_PERFORM_OP, - EEPROM_OVERFLOW_ERROR, - TWO_UINT32_TO_UINT64( - i2cInfo.offset, - io_buflen ), - i2cInfo.devSize_KB, - true /*Add HB SW Callout*/ ); - - err->collectTrace( EEPROM_COMP_NAME ); - + "eepromPerformOp() An error occured trying to resolve what source to perform op on (CACHE or HARDWARE)"); break; } - // Adjust offset and devAddr to the correct starting chip - while( i2cInfo.offset >= l_snglChipSize ) - { - i2cInfo.offset -= l_snglChipSize; - i2cInfo.devAddr += EEPROM_DEVADDR_INC; - } - - // Keep first op length within a chip - if( ( i2cInfo.offset + io_buflen ) > l_snglChipSize ) + if(l_source == EEPROM::CACHE ) { - l_currentOpLen = l_snglChipSize - i2cInfo.offset; - } - - TRACFCOMP( g_trac_eeprom, - "eepromPerformOp(): i_opType=%d " - "C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X, ", - i_opType, i2cInfo.eepromRole, i2cInfo.engine, - i2cInfo.port, i2cInfo.devAddr, i2cInfo.offset, io_buflen) - - TRACFCOMP (g_trac_eeprom, - "eepromPerformOp(): snglChipKB=0x%X, chipCount=0x%X, devSizeKB=0x%X", - l_snglChipSize, i2cInfo.chipCount, i2cInfo.devSize_KB); - - // Printing mux info separately, if combined, nothing is displayed - char* l_muxPath = i2cInfo.i2cMuxPath.toString(); - TRACFCOMP(g_trac_eeprom, "eepromPerformOp(): " - "muxSelector=0x%X, muxPath=%s", - i2cInfo.i2cMuxBusSelector, - l_muxPath); - free(l_muxPath); - l_muxPath = nullptr; + // Read the copy of the EEPROM data we have cached in PNOR + err = eepromPerformOpCache(i_opType, i_target, io_buffer, io_buflen, i2cInfo); -#ifdef __HOSTBOOT_RUNTIME - // Disable Sensor Cache if the I2C master target is MEMBUF - if( i2cMasterTarget->getAttr<TARGETING::ATTR_TYPE>() == - TARGETING::TYPE_MEMBUF ) - { - err = I2C::i2cDisableSensorCache(i2cMasterTarget,scacDisabled); - if ( err ) - { - break; - } - } -#endif //__HOSTBOOT_RUNTIME - - // Do the read or write - while(l_remainingOpLen > 0) - { - if( i_opType == DeviceFW::READ ) - { - err = eepromRead( i2cMasterTarget, - l_pBuffer, - l_currentOpLen, - i2cInfo ); - } - else if( i_opType == DeviceFW::WRITE ) - { - err = eepromWrite( i2cMasterTarget, - l_pBuffer, - l_currentOpLen, - i2cInfo ); - } - else - { - TRACFCOMP( g_trac_eeprom, - ERR_MRK"eepromPerformOp(): " - "Invalid EEPROM Operation!"); - - /*@ - * @errortype - * @reasoncode EEPROM_INVALID_OPERATION - * @severity ERRL_SEV_UNRECOVERABLE - * @moduleid EEPROM_PERFORM_OP - * @userdata1 Operation Type - * @userdata2 Chip to Access - * @devdesc Invalid operation type. - */ - err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - EEPROM_PERFORM_OP, - EEPROM_INVALID_OPERATION, - i_opType, - i2cInfo.eepromRole, - true /*Add HB SW Callout*/ ); - - err->collectTrace( EEPROM_COMP_NAME ); - } - - if ( err ) + if(err) { break; } - // Adjust the buffer pointer and remaining op length - l_pBuffer = (void *)(reinterpret_cast<uint64_t>(l_pBuffer) - + l_currentOpLen); - l_remainingOpLen -= l_currentOpLen; - - if( l_remainingOpLen > l_snglChipSize ) + // If the operation is a write we also need to "write through" to HW after + // we write cache + if(i_opType == DeviceFW::WRITE) { - // Keep next op length within a chip - l_currentOpLen = l_snglChipSize; + err = eepromPerformOpHW(i_opType, i_target, io_buffer, io_buflen, i2cInfo); } - else if( l_remainingOpLen > 0 ) - { - // Set next op length to what is left to do - l_currentOpLen = l_remainingOpLen; - } - else - { - // Break if there is nothing left to do - break; - } - - // Prepare the address at the start of next EEPROM - i2cInfo.offset = 0; - i2cInfo.devAddr += EEPROM_DEVADDR_INC; - } // Do the read or write - } while( 0 ); - -#ifdef __HOSTBOOT_RUNTIME - // Re-enable sensor cache if it was disabled before the eeprom op and - // the I2C master target is MEMBUF - if( scacDisabled && - (i2cMasterTarget->getAttr<TARGETING::ATTR_TYPE>() == TARGETING::TYPE_MEMBUF) ) - { - errlHndl_t tmp_err = NULL; - - tmp_err = I2C::i2cEnableSensorCache(i2cMasterTarget); - - if( err && tmp_err) - { - delete tmp_err; - TRACFCOMP(g_trac_eeprom, - ERR_MRK" Enable Sensor Cache failed for HUID=0x%.8X", - TARGETING::get_huid(i2cMasterTarget)); - } - else if(tmp_err) - { - err = tmp_err; - } - } -#endif //__HOSTBOOT_RUNTIME - - // If there is an error, add parameter info to log - if ( err != NULL ) - { - EEPROM::UdEepromParms( i_opType, - i_target, - io_buflen, - i2cInfo ) - .addToLog(err); - } - - TRACDCOMP( g_trac_eeprom, - EXIT_MRK"eepromPerformOp() - %s", - ((NULL == err) ? "No Error" : "With Error") ); - - return err; -} // end eepromPerformOp - -#ifndef __HOSTBOOT_RUNTIME -//------------------------------------------------------------------- -//eepromPresence -//------------------------------------------------------------------- -bool eepromPresence ( TARGETING::Target * i_target ) -{ - TRACUCOMP(g_trac_eeprom, ENTER_MRK"eepromPresence()"); - - errlHndl_t err = NULL; - bool l_present = false; - TARGETING::Target * i2cMasterTarget = NULL; - - eeprom_addr_t i2cInfo; - - i2cInfo.eepromRole = EEPROM::VPD_PRIMARY; - i2cInfo.offset = 0; - do - { - - // Read Attributes needed to complete the operation - err = eepromReadAttributes( i_target, - i2cInfo ); - - if( err ) - { - TRACFCOMP(g_trac_eeprom, - ERR_MRK"Error in eepromPresence::eepromReadAttributes()"); - break; } - - // Check to see if we need to find a new target for - // the I2C Master - err = eepromGetI2CMasterTarget( i_target, - i2cInfo, - i2cMasterTarget ); - - if( err ) + else if(l_source == EEPROM::HARDWARE) { - TRACFCOMP(g_trac_eeprom, - ERR_MRK"Error in eepromPresence::eepromGetI2Cmaster()"); - break; + // Read from the actual physical EEPROM device + err = eepromPerformOpHW(i_opType, i_target, io_buffer, io_buflen, i2cInfo); } + #else - //Check for the target at the I2C level - l_present = I2C::i2cPresence(i2cMasterTarget, - i2cInfo.port, - i2cInfo.engine, - i2cInfo.devAddr, - i2cInfo.i2cMuxBusSelector, - i2cInfo.i2cMuxPath); + // Read from the actual physical EEPROM device + err = eepromPerformOpHW(i_opType, i_target, io_buffer, io_buflen, i2cInfo); - if( !l_present ) - { - TRACDCOMP(g_trac_eeprom, - ERR_MRK"i2cPresence returned false! chip NOT present!"); - break; - } + #endif // CONFIG_SUPPORT_EEPROM_CACHING - } while( 0 ); - // If there was an error commit the error log - if( err ) - { - errlCommit( err, I2C_COMP_ID ); - } - - TRACDCOMP(g_trac_eeprom, EXIT_MRK"eepromPresence()"); - return l_present; -} -#endif - - - -// ------------------------------------------------------------------ -// eepromPageOp -// ------------------------------------------------------------------ -errlHndl_t eepromPageOp( TARGETING::Target * i_target, - bool i_switchPage, - bool i_lockMutex, - bool & io_pageLocked, - uint8_t i_desiredPage, - eeprom_addr_t i_i2cInfo ) -{ - TRACUCOMP(g_trac_eeprom, - ENTER_MRK"eepromPageOp()"); - - errlHndl_t l_err = NULL; - size_t l_placeHolderZero = 0; - - do - { - // DDR4 requires EEPROM page to be selected before read/write operation. - // The following operation locks the EEPROM_PAGE attribute behind a - // mutex and switches all DIMMs on the I2C bus to the appropriate - // page. - if( i_i2cInfo.addrSize == ONE_BYTE_ADDR_PAGESELECT ) - { - - bool l_lockPage; - if( i_switchPage ) - { - // we want to switch to the desired page - l_lockPage = true; - l_err = deviceOp( DeviceFW::WRITE, - i_target, - NULL, - l_placeHolderZero, - DEVICE_I2C_CONTROL_PAGE_OP( - i_i2cInfo.port, - i_i2cInfo.engine, - l_lockPage, - i_desiredPage, - i_lockMutex )); - - if( l_err ) - { - TRACFCOMP(g_trac_eeprom, - "eepromPageOp::Failed locking EEPROM page"); - break; - } - // if we make it this far, we successfully locked the page mutex - io_pageLocked = true; - } - else - { - // we only want to unlock the page - l_lockPage = false; - l_err = deviceOp( DeviceFW::WRITE, - i_target, - NULL, - l_placeHolderZero, - DEVICE_I2C_CONTROL_PAGE_OP( - i_i2cInfo.port, - i_i2cInfo.engine, - l_lockPage, - l_placeHolderZero, - i_lockMutex )); - - if( l_err ) - { - TRACFCOMP( g_trac_eeprom, - "eepromPageOp()::failed unlocking EEPROM page"); - break; - } - // if we make it this far, we successfully unlocked the page - io_pageLocked = false; - } - } }while(0); - TRACUCOMP(g_trac_eeprom, - EXIT_MRK"eepromPageOp()"); - return l_err; -} - - -// ------------------------------------------------------------------ -// crossesEepromPageBoundary -// ------------------------------------------------------------------ -bool crossesEepromPageBoundary( uint64_t i_originalOffset, - size_t i_originalLen, - size_t & io_newLen, - size_t & o_pageTwoBuflen, - eeprom_addr_t i_i2cInfo ) -{ - bool l_boundaryCrossed = false; - size_t l_higherBound = i_originalOffset + i_originalLen; - - if( ( i_i2cInfo.addrSize == ONE_BYTE_ADDR_PAGESELECT ) && - ( ( i_originalOffset < EEPROM_PAGE_SIZE ) && - ( l_higherBound > EEPROM_PAGE_SIZE) ) ) - { - // The read/write request crosses the boundary - l_boundaryCrossed = true; - - // Calculate the new length of the page 0 buffer and the - // length of the page 1 buffer - o_pageTwoBuflen = l_higherBound - EEPROM_PAGE_SIZE; - io_newLen = i_originalLen - o_pageTwoBuflen; - } - else - { - // The read/write request does not cross the boundary. - // Update new length to be used by subsequent operations - io_newLen = i_originalLen; - o_pageTwoBuflen = 0; - } - - return l_boundaryCrossed; -} - - - -// ------------------------------------------------------------------ -// eepromRead -// ------------------------------------------------------------------ -errlHndl_t eepromRead ( TARGETING::Target * i_target, - void * o_buffer, - size_t i_buflen, - eeprom_addr_t i_i2cInfo ) -{ - errlHndl_t err = NULL; - uint8_t byteAddr[MAX_BYTE_ADDR]; - size_t byteAddrSize = 0; - bool l_pageLocked = false; - uint8_t l_desiredPage = 0; - bool l_boundaryCrossed = false; - size_t l_readBuflen = 0; - size_t l_pageTwoBuflen = 0; - - TRACUCOMP( g_trac_eeprom, - ENTER_MRK"eepromRead()" ); - - do - { - TRACUCOMP( g_trac_eepromr, - "EEPROM READ START : Chip: %02d : Offset %.2X : Len %d", - i_i2cInfo.chip, i_i2cInfo.offset, i_buflen ); - - // At maximum we want to do 1 KB reads at a time. The largest that - // the scom byte range will support is 64 KB - 1 but we will do 1 - // KB at a time to catch fails faster. This is useful when we do big - // reads when caching the eeprom to pnor. - size_t l_readLenRemaining = i_buflen; - size_t l_currentReadLen; - - // Lock to sequence operations - mutex_lock( &g_eepromMutex ); - - while( l_readLenRemaining > 0 ) - { - l_currentReadLen = l_readLenRemaining < KILOBYTE ? l_readLenRemaining : KILOBYTE; - - // Check to see if the Read operation straddles the EEPROM page - // boundary.Note this is only required for systems w/ DDR4 industry - // standard dimms. DDR4 ISDIMMS have a max of 512 bytes so we will - // never loop through this multiple times on those systems - l_boundaryCrossed = crossesEepromPageBoundary( i_i2cInfo.offset, - l_currentReadLen, - l_readBuflen, - l_pageTwoBuflen, - i_i2cInfo ); - - // Set addressing parameters - err = eepromPrepareAddress( i_target, - &byteAddr, - byteAddrSize, - l_desiredPage, - i_i2cInfo); - - if( err ) - { - TRACFCOMP(g_trac_eeprom, - ERR_MRK"eepromRead()::eepromPrepareAddress()"); - break; - } - - - // Attempt to lock page mutex - // (only important in DDR4 IS-DIMM systems) - bool l_switchPage = true; - bool l_lockMutex = true; - err = eepromPageOp( i_target, - l_switchPage, - l_lockMutex, - l_pageLocked, - l_desiredPage, - i_i2cInfo ); - - if( err ) - { - TRACFCOMP(g_trac_eeprom, - "eepromRead()::eepromPageOp()::failed locking page"); - break; - } - - // First Read. If Second read is necessary, this call will read - // everything from the original offset up to the 256th byte - err = eepromReadData( i_target, - &(reinterpret_cast<uint8_t*>(o_buffer)[i_buflen - l_readLenRemaining]), - l_readBuflen, - &byteAddr, - byteAddrSize, - i_i2cInfo ); - - i_i2cInfo.offset += l_currentReadLen; - l_readLenRemaining -= l_currentReadLen; - - if( err ) - { - TRACFCOMP(g_trac_eeprom, - "Failed reading data: original read"); - break; - } - - - // Perform the second Read if necessary. Read starts at - // begining of EEPROM page 1 (offset=0x100) and reads the - // rest of the required data. - if( l_boundaryCrossed ) - { - //Prepare the address to read at the start of EEPROM page one - i_i2cInfo.offset = EEPROM_PAGE_SIZE; // 0x100 - err = eepromPrepareAddress( i_target, - &byteAddr, - byteAddrSize, - l_desiredPage, - i_i2cInfo ); - if( err ) - { - TRACFCOMP(g_trac_eeprom, - "Error preparing address: second eeprom read"); - break; - } - - // Switch to the second EEPROM page - l_switchPage = true; - l_lockMutex = false; - err = eepromPageOp( i_target, - l_switchPage, - l_lockMutex, - l_pageLocked, - l_desiredPage, - i_i2cInfo ); - - if( err ) - { - TRACFCOMP( g_trac_eeprom, - "Failed switching to EEPROM page 1 for second read op"); - break; - } - - // Perform the second read operation - err = eepromReadData( - i_target, - &(reinterpret_cast<uint8_t*>(o_buffer)[l_readBuflen]), - l_pageTwoBuflen, - &byteAddr, - byteAddrSize, - i_i2cInfo ); - - if( err ) - { - TRACFCOMP( g_trac_eeprom, - "Failed reading data: second read"); - break; - } - } - } - - - TRACUCOMP( g_trac_eepromr, - "EEPROM READ END : Eeprom Role: %02d : Offset %.2X : Len %d : %016llx", - i_i2cInfo.eepromRole, i_i2cInfo.offset, i_buflen, - *((uint64_t*)o_buffer) ); - - } while( 0 ); - - // Unlock eeprom mutex no matter what - mutex_unlock( & g_eepromMutex ); - - // Whether we failed in the main routine or not, unlock page iff the page is locked - if( l_pageLocked ) - { - errlHndl_t l_pageOpErrl = NULL; - bool l_switchPage = false; - bool l_lockMutex = false; - l_pageOpErrl = eepromPageOp( i_target, - l_switchPage, - l_lockMutex, - l_pageLocked, - l_desiredPage, - i_i2cInfo ); - if( l_pageOpErrl ) - { - TRACFCOMP(g_trac_eeprom, - "eepromRead()::Failed unlocking page"); - errlCommit(l_pageOpErrl, I2C_COMP_ID); - } - - } - - TRACUCOMP( g_trac_eeprom, - EXIT_MRK"eepromRead()" ); - - return err; -} // end eepromRead - - -// ------------------------------------------------------------------ -// eepromReadData -// ------------------------------------------------------------------ -errlHndl_t eepromReadData( TARGETING::Target * i_target, - void * o_buffer, - size_t i_buflen, - void * i_byteAddress, - size_t i_byteAddressSize, - eeprom_addr_t i_i2cInfo ) -{ - errlHndl_t l_err = NULL; - errlHndl_t err_retryable = NULL; - - TRACUCOMP(g_trac_eeprom, - ENTER_MRK"eepromReadData()"); - do - { - /************************************************************/ - /* Attempt read multiple times ONLY on retryable fails */ - /************************************************************/ - for (uint8_t retry = 0; - retry <= EEPROM_MAX_RETRIES; - retry++) - { - - // Only write the byte address if we have data to write - if( 0 != i_byteAddressSize ) - { - // Use the I2C MUX OFFSET Interface for the READ - l_err = deviceOp( DeviceFW::READ, - i_target, - o_buffer, - i_buflen, - DEVICE_I2C_ADDRESS_OFFSET( - i_i2cInfo.port, - i_i2cInfo.engine, - i_i2cInfo.devAddr, - i_byteAddressSize, - reinterpret_cast<uint8_t*>(i_byteAddress), - i_i2cInfo.i2cMuxBusSelector, - &(i_i2cInfo.i2cMuxPath))); - - if( l_err ) - { - TRACFCOMP(g_trac_eeprom, - ERR_MRK"eepromReadData(): I2C Read-Offset failed on " - "%d/%d/0x%X aS=%d", - i_i2cInfo.port, i_i2cInfo.engine, - i_i2cInfo.devAddr, i_byteAddressSize); - TRACFBIN(g_trac_eeprom, "i_byteAddress[]", - i_byteAddress, i_byteAddressSize); - - // Don't break here -- error handled below - } - } - else - { - // Do the actual read via I2C - l_err = deviceOp( DeviceFW::READ, - i_target, - o_buffer, - i_buflen, - DEVICE_I2C_ADDRESS( - i_i2cInfo.port, - i_i2cInfo.engine, - i_i2cInfo.devAddr, - i_i2cInfo.i2cMuxBusSelector, - &(i_i2cInfo.i2cMuxPath) ) ); - - if( l_err ) - { - TRACFCOMP(g_trac_eeprom, - ERR_MRK"eepromReadData(): I2C Read failed on " - "%d/%d/0x%0X", i_i2cInfo.port, i_i2cInfo.engine, - i_i2cInfo.devAddr); - - // Don't break here -- error handled below - } - } - - if ( l_err == NULL ) - { - // Operation completed successfully - // break from retry loop - break; - } - else if ( !errorIsRetryable( l_err->reasonCode() ) ) - { - // Only retry on errorIsRetryable() failures: break from retry loop - TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): Non-Nack " - "Error: rc=0x%X, tgt=0x%X, No Retry (retry=%d)", - l_err->reasonCode(), - TARGETING::get_huid(i_target), retry); - - l_err->collectTrace(EEPROM_COMP_NAME); - - // break from retry loop - break; - } - else // Handle retryable error - { - // If op will be attempted again: save log and continue - if ( retry < EEPROM_MAX_RETRIES ) - { - // Only save original retryable error - if ( err_retryable == NULL ) - { - // Save original retryable error - err_retryable = l_err; - - TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): " - "Retryable Error rc=0x%X, eid=0x%X, tgt=0x%X, " - "retry/MAX=%d/%d. Save error and retry", - err_retryable->reasonCode(), - err_retryable->eid(), - TARGETING::get_huid(i_target), - retry, EEPROM_MAX_RETRIES); - - err_retryable->collectTrace(EEPROM_COMP_NAME); - } - else - { - // Add data to original retryable error - TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): " - "Another Retryable Error rc=0x%X, eid=0x%X " - "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. " - "Delete error and retry", - l_err->reasonCode(), l_err->eid(), l_err->plid(), - TARGETING::get_huid(i_target), - retry, EEPROM_MAX_RETRIES); - - ERRORLOG::ErrlUserDetailsString( - "Another Retryable ERROR found") - .addToLog(err_retryable); - - // Delete this new retryable error - delete l_err; - l_err = NULL; - } - - // continue to retry - continue; - } - else // no more retries: trace and break - { - TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): " - "Error rc=0x%X, eid=%d, tgt=0x%X. No More " - "Retries (retry/MAX=%d/%d). Returning Error", - l_err->reasonCode(), l_err->eid(), - TARGETING::get_huid(i_target), - retry, EEPROM_MAX_RETRIES); - - l_err->collectTrace(EEPROM_COMP_NAME); - - // break from retry loop - break; - } - } - - } // end of retry loop - - // Handle saved retryable error, if any - if (err_retryable) - { - if (l_err) - { - // commit original retryable error with new err PLID - err_retryable->plid(l_err->plid()); - TRACFCOMP(g_trac_eeprom, "eepromReadData(): Committing saved retryable " - "l_err eid=0x%X with plid of returned err: 0x%X", - err_retryable->eid(), err_retryable->plid()); - - ERRORLOG::ErrlUserDetailsTarget(i_target) - .addToLog(err_retryable); - - errlCommit(err_retryable, EEPROM_COMP_ID); - } - else - { - // Since we eventually succeeded, delete original retryable error - TRACFCOMP(g_trac_eeprom, "eepromReadData(): Op successful, " - "deleting saved retryable err eid=0x%X, plid=0x%X", - err_retryable->eid(), err_retryable->plid()); - - delete err_retryable; - err_retryable = NULL; - } - } - - }while( 0 ); - - TRACUCOMP(g_trac_eeprom, - EXIT_MRK"eepromReadData"); - return l_err; -} - - - -// ------------------------------------------------------------------ -// eepromWrite -// ------------------------------------------------------------------ -errlHndl_t eepromWrite ( TARGETING::Target * i_target, - void * io_buffer, - size_t & io_buflen, - eeprom_addr_t i_i2cInfo ) -{ - errlHndl_t err = NULL; - uint8_t l_desiredPage = 0; - uint8_t l_originalPage = 0; - uint8_t byteAddr[MAX_BYTE_ADDR]; - size_t byteAddrSize = 0; - uint8_t * newBuffer = NULL; - bool needFree = false; - bool unlock = false; - bool l_pageLocked = false; - uint32_t data_left = 0; - uint32_t diff_wps = 0; - size_t l_writeBuflen = 0; - size_t l_bytesIntoSecondPage = 0; - - TRACDCOMP( g_trac_eeprom, - ENTER_MRK"eepromWrite()" ); - - do - { - TRACUCOMP( g_trac_eeprom, - "EEPROM WRITE START : Eeprom Role : %02d : Offset %.2X : Len %d : %016llx", - i_i2cInfo.eepromRole, i_i2cInfo.offset, io_buflen, - *((uint64_t*)io_buffer) ); - - - // Prepare address parameters - err = eepromPrepareAddress( i_target, - &byteAddr, - byteAddrSize, - l_desiredPage, - i_i2cInfo); - - if( err ) - { - TRACFCOMP(g_trac_eeprom, - ERR_MRK"eepromWrite()::eepromPrepareAddress()"); - break; - } - - // Save original Page - l_originalPage = l_desiredPage; - // Attempt to lock page mutex - bool l_switchPage = true; // true: Lock and switch page - // false: Just unlock page - bool l_lockMutex = true; // true: Lock mutex - // false: Skip locking mutex step - err = eepromPageOp( i_target, - l_switchPage, - l_lockMutex, - l_pageLocked, - l_desiredPage, - i_i2cInfo ); - - if( err ) - { - TRACFCOMP(g_trac_eeprom, - "eepromWrite()::Failed locking EEPROM page"); - break; - } - - // Check for writePageSize of zero - if ( i_i2cInfo.writePageSize == 0 ) - { - TRACFCOMP( g_trac_eeprom, - ERR_MRK"eepromWrite(): writePageSize is 0!"); - - /*@ - * @errortype - * @reasoncode EEPROM_I2C_WRITE_PAGE_SIZE_ZERO - * @severity ERRL_SEV_UNRECOVERABLE - * @moduleid EEPROM_WRITE - * @userdata1 HUID of target - * @userdata2 Chip to Access - * @devdesc I2C write page size is zero. - */ - err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - EEPROM_WRITE, - EEPROM_I2C_WRITE_PAGE_SIZE_ZERO, - TARGETING::get_huid(i_target), - i_i2cInfo.eepromRole, - true /*Add HB SW Callout*/ ); - err->collectTrace( EEPROM_COMP_NAME ); - - break; - } - - // EEPROM devices have write page boundaries, so when necessary - // need to split up command into multiple write operations - - // Setup a max-size buffer of writePageSize - size_t newBufLen = i_i2cInfo.writePageSize; - newBuffer = static_cast<uint8_t*>(malloc( newBufLen )); - needFree = true; - - // Point a uint8_t ptr at io_buffer for array addressing below - uint8_t * l_data_ptr = reinterpret_cast<uint8_t*>(io_buffer); - - // Lock for operation sequencing - mutex_lock( &g_eepromMutex ); - unlock = true; - - // variables to store different amount of data length - size_t loop_data_length = 0; - size_t total_bytes_written = 0; - - while( total_bytes_written < io_buflen ) - { - // Determine how much data can be written in this loop - // Can't go over a writePageSize boundary - - // Total data left to write - data_left = io_buflen - total_bytes_written; - - // Difference to next writePageSize boundary - diff_wps = i_i2cInfo.writePageSize - - (i_i2cInfo.offset % i_i2cInfo.writePageSize); - - // Take the lesser of the 2 options - loop_data_length = (data_left < diff_wps ) ? data_left : diff_wps; - - // Add the data the user wanted to write - memcpy( newBuffer, - &l_data_ptr[total_bytes_written], - loop_data_length ); - - - - // Check if loop_data_length crosses the EEPROM page boundary - crossesEepromPageBoundary( i_i2cInfo.offset, - loop_data_length, - l_writeBuflen, - l_bytesIntoSecondPage, - i_i2cInfo ); - - // Setup offset/address parms - err = eepromPrepareAddress( i_target, - &byteAddr, - byteAddrSize, - l_desiredPage, - i_i2cInfo ); - - - if( err ) - { - TRACFCOMP(g_trac_eeprom, - ERR_MRK"eepromWrite::eepromPrepareAddress()::loop version"); - break; - } - - - - // if desired page has changed mid-request, switch to correct page - if( l_desiredPage != l_originalPage ) - { - l_switchPage = true; - l_lockMutex = false; - err = eepromPageOp( i_target, - l_switchPage, - l_lockMutex, - l_pageLocked, - l_desiredPage, - i_i2cInfo ); - if( err ) - { - TRACFCOMP( g_trac_eeprom, - "Failed switching to new EEPROM page!"); - break; - } - l_originalPage = l_desiredPage; - } - - TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop: %d/%d/0x%X " - "writeBuflen=%d, offset=0x%X, bAS=%d, diffs=%d/%d", - i_i2cInfo.port, i_i2cInfo.engine, i_i2cInfo.devAddr, - l_writeBuflen, i_i2cInfo.offset, byteAddrSize, - data_left, diff_wps); - - // Perform the requested write operation - err = eepromWriteData( i_target, - newBuffer, - l_writeBuflen, - &byteAddr, - byteAddrSize, - i_i2cInfo ); - - if ( err ) - { - // Can't assume that anything was written if - // there was an error, so no update to total_bytes_written - // for this loop - TRACFCOMP(g_trac_eeprom, - "Failed writing data: original eeprom write"); - break; - } - - // Wait for EEPROM to write data to its internal memory - // i_i2cInfo.writeCycleTime value in milliseconds - nanosleep( 0, i_i2cInfo.writeCycleTime * NS_PER_MSEC ); - - // Update how much data was written - total_bytes_written += l_writeBuflen; - - // Update offset - i_i2cInfo.offset += l_writeBuflen; - - TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop End: " - "writeBuflen=%d, offset=0x%X, t_b_w=%d, io_buflen=%d", - l_writeBuflen, i_i2cInfo.offset, - total_bytes_written, io_buflen); - } // end of write for-loop - - // Release mutex lock - mutex_unlock( &g_eepromMutex ); - unlock = false; - - - // Set how much data was actually written - io_buflen = total_bytes_written; - - - TRACSCOMP( g_trac_eepromr, - "EEPROM WRITE END : Eeprom Role : %02d : Offset %.2X : Len %d", - i_i2cInfo.eepromRole, i_i2cInfo.offset, io_buflen ); - } while( 0 ); - - // Free memory - if( needFree ) - { - free( newBuffer ); - } - - // Catch it if we break out early. - if( unlock ) - { - mutex_unlock( & g_eepromMutex ); - } - - - // Whether we failed in the main routine or not, unlock the page iff it is already - // locked - if( l_pageLocked ) - { - errlHndl_t l_pageOpErrl = NULL; - - bool l_switchPage = false; - bool l_lockMutex = false; - l_pageOpErrl = eepromPageOp( i_target, - l_switchPage, - l_lockMutex, - l_pageLocked, - l_desiredPage, - i_i2cInfo ); - if( l_pageOpErrl ) - { - TRACFCOMP(g_trac_eeprom, - "eepromWrite()::Failed unlocking page"); - errlCommit(l_pageOpErrl, I2C_COMP_ID); - } - - } TRACDCOMP( g_trac_eeprom, - EXIT_MRK"eepromWrite()" ); - - return err; - -} // end eepromWrite - - - -// ------------------------------------------------------------------ -// eepromWriteData -// ------------------------------------------------------------------ -errlHndl_t eepromWriteData( TARGETING::Target * i_target, - void * i_dataToWrite, - size_t i_dataLen, - void * i_byteAddress, - size_t i_byteAddressSize, - eeprom_addr_t i_i2cInfo ) -{ - TRACDCOMP( g_trac_eeprom, - ENTER_MRK"eepromWriteData()"); - errlHndl_t err = NULL; - errlHndl_t err_retryable = NULL; - do - { - /***********************************************************/ - /* Attempt write multiple times ONLY on retryable fails */ - /***********************************************************/ - for (uint8_t retry = 0; - retry <= EEPROM_MAX_RETRIES; - retry++) - { - // Do the actual data write - err = deviceOp( DeviceFW::WRITE, - i_target, - i_dataToWrite, - i_dataLen, - DEVICE_I2C_ADDRESS_OFFSET( - i_i2cInfo.port, - i_i2cInfo.engine, - i_i2cInfo.devAddr, - i_byteAddressSize, - reinterpret_cast<uint8_t*>( - i_byteAddress), - i_i2cInfo.i2cMuxBusSelector, - &(i_i2cInfo.i2cMuxPath) ) ); - - if ( err == NULL ) - { - // Operation completed successfully - // break from retry loop - break; - } - else if ( !errorIsRetryable( err->reasonCode() ) ) - { - // Only retry on errorIsRetryable() failures: break from retry loop - TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData(): I2C " - "Write Non-Retryable fail %d/%d/0x%X, " - "ldl=%d, offset=0x%X, aS=%d, retry=%d", - i_i2cInfo.port, i_i2cInfo.engine, - i_i2cInfo.devAddr, i_dataLen, - i_i2cInfo.offset, i_i2cInfo.addrSize, retry); - - err->collectTrace(EEPROM_COMP_NAME); - - // break from retry loop - break; - } - else // Handle retryable error - { - TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData(): I2C " - "Write retryable fail %d/%d/0x%X, " - "ldl=%d, offset=0x%X, aS=%d, writePageSize = %x", - i_i2cInfo.port, i_i2cInfo.engine, - i_i2cInfo.devAddr, i_dataLen, - i_i2cInfo.offset, i_i2cInfo.addrSize, - i_i2cInfo.writePageSize); - - // Printing mux info separately, if combined, nothing is displayed - char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); - TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData():" - "muxSelector=0x%X, muxPath=%s", - i_i2cInfo.i2cMuxBusSelector, - l_muxPath); - free(l_muxPath); - l_muxPath = nullptr; - - // If op will be attempted again: save error and continue - if ( retry < EEPROM_MAX_RETRIES ) - { - // Only save original retryable error - if ( err_retryable == NULL ) - { - // Save original retryable error - err_retryable = err; - - TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): " - "Error rc=0x%X, eid=0x%X plid=0x%X, " - "tgt=0x%X, retry/MAX=%d/%d. Save error " - "and retry", - err_retryable->reasonCode(), - err_retryable->eid(), - err_retryable->plid(), - TARGETING::get_huid(i_target), - retry, EEPROM_MAX_RETRIES); - - err_retryable->collectTrace(EEPROM_COMP_NAME); - } - else - { - // Add data to original retryable error - TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): " - "Another Retryable Error rc=0x%X, eid=0x%X " - "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. " - "Delete error and retry", - err->reasonCode(), err->eid(), - err->plid(), - TARGETING::get_huid(i_target), - retry, EEPROM_MAX_RETRIES); - - ERRORLOG::ErrlUserDetailsString( - "Another retryable ERROR found") - .addToLog(err_retryable); - - // Delete this new retryable error - delete err; - err = NULL; - } - - // continue to retry - continue; - } - else // no more retries: trace and break - { - TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): " - "Error rc=0x%X, tgt=0x%X. No More Retries " - "(retry/MAX=%d/%d). Returning Error", - err->reasonCode(), - TARGETING::get_huid(i_target), - retry, EEPROM_MAX_RETRIES); - - err->collectTrace(EEPROM_COMP_NAME); - - // break from retry loop - break; - } - } - - } // end of retry loop - /***********************************************************/ - - // Handle saved retryable errors, if any - if (err_retryable) - { - if (err) - { - // commit original retryable error with new err PLID - err_retryable->plid(err->plid()); - TRACFCOMP(g_trac_eeprom, "eepromWriteData(): Committing saved " - "retryable err eid=0x%X with plid of returned err: " - "0x%X", - err_retryable->eid(), err_retryable->plid()); - - ERRORLOG::ErrlUserDetailsTarget(i_target) - .addToLog(err_retryable); - - errlCommit(err_retryable, EEPROM_COMP_ID); - } - else - { - // Since we eventually succeeded, delete original retryable error - TRACFCOMP(g_trac_eeprom, "eepromWriteData(): Op successful, " - "deleting saved retryable err eid=0x%X, plid=0x%X", - err_retryable->eid(), err_retryable->plid()); - - delete err_retryable; - err_retryable = NULL; - } - } - }while( 0 ); - TRACDCOMP( g_trac_eeprom, - EXIT_MRK"eepromWriteData()"); - return err; -} - - - -// ------------------------------------------------------------------ -// eepromPrepareAddress -// ------------------------------------------------------------------ -errlHndl_t eepromPrepareAddress ( TARGETING::Target * i_target, - void * io_buffer, - size_t & o_bufSize, - uint8_t & o_desiredPage, - eeprom_addr_t i_i2cInfo ) -{ - errlHndl_t err = NULL; - o_bufSize = 0; - - TRACDCOMP( g_trac_eeprom, - ENTER_MRK"eepromPrepareAddress()" ); - - do - { - - // -------------------------------------------------------------------- - // Currently only supporting I2C devices and that use 0, 1, or 2 bytes - // to set the offset (ie, internal address) into the device. - // -------------------------------------------------------------------- - switch( i_i2cInfo.addrSize ) - { - case TWO_BYTE_ADDR: - o_bufSize = 2; - memset( io_buffer, 0x0, o_bufSize ); - *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFF00ull) >> 8; - *((uint8_t*)io_buffer+1) = (i_i2cInfo.offset & 0x00FFull); - break; - - case ONE_BYTE_ADDR_PAGESELECT: - // If the offset is less than 256 bytes, report page zero, else page 1 - if( i_i2cInfo.offset >= EEPROM_PAGE_SIZE ) - { - o_desiredPage = 1; - } - else - { - o_desiredPage = 0; - } - o_bufSize = 1; - memset( io_buffer, 0x0, o_bufSize ); - *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFFull); - break; - - case ONE_BYTE_ADDR: - o_bufSize = 1; - memset( io_buffer, 0x0, o_bufSize ); - *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFFull); - break; - - case ZERO_BYTE_ADDR: - o_bufSize = 0; - // nothing to do with the buffer in this case - break; - - default: - TRACFCOMP( g_trac_eeprom, - ERR_MRK"eepromPrepareAddress() - Invalid Device " - "Address Size: 0x%08x", i_i2cInfo.addrSize); - - /*@ - * @errortype - * @reasoncode EEPROM_INVALID_DEVICE_TYPE - * @severity ERRL_SEV_UNRECOVERABLE - * @moduleid EEPROM_PREPAREADDRESS - * @userdata1 Address Size (aka Device Type) - * @userdata2 EEPROM chip - * @devdesc The Device type not supported (addrSize) - * @custdesc A problem was detected during the IPL of - * the system: Device type not supported. - */ - err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - EEPROM_PREPAREADDRESS, - EEPROM_INVALID_DEVICE_TYPE, - i_i2cInfo.addrSize, - i_i2cInfo.eepromRole, - true /*Add HB SW Callout*/ ); - - err->collectTrace( EEPROM_COMP_NAME ); - - break; - } - - } while( 0 ); - - TRACDCOMP( g_trac_eeprom, - EXIT_MRK"eepromPrepareAddress()" ); - - return err; -} // end eepromPrepareAddress - - -// ------------------------------------------------------------------ -// eepromReadAttributes -// ------------------------------------------------------------------ -errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target, - eeprom_addr_t & o_i2cInfo ) -{ - errlHndl_t err = NULL; - bool fail_reading_attribute = false; - - TRACDCOMP( g_trac_eeprom, - ENTER_MRK"eepromReadAttributes() huid=0x%.8X", - TARGETING::get_huid(i_target) ); - - // These variables will be used to hold the EEPROM attribute data - // Note: each 'EepromVpd' struct is kept the same via the attributes - // so will be copying each to eepromData to save code space - TARGETING::EepromVpdPrimaryInfo eepromData; - - do - { - - switch (o_i2cInfo.eepromRole ) - { - case VPD_PRIMARY: - if( !( i_target-> - tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO> - ( eepromData ) ) ) - - { - fail_reading_attribute = true; - } - break; - - case VPD_BACKUP: - - if( !(i_target-> - tryGetAttr<TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO> - ( reinterpret_cast< - TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO_type&> - ( eepromData) ) ) ) - { - fail_reading_attribute = true; - } - break; - - case SBE_PRIMARY: - if( !(i_target-> - tryGetAttr<TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO> - ( reinterpret_cast< - TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO_type&> - ( eepromData) ) ) ) - { - fail_reading_attribute = true; - } - break; - - case SBE_BACKUP: - if( (!i_target-> - tryGetAttr<TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO> - ( reinterpret_cast< - TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO_type&> - ( eepromData) ) ) ) - { - fail_reading_attribute = true; - } - break; - - default: - TRACFCOMP( g_trac_eeprom,ERR_MRK"eepromReadAttributes() - " - "Invalid chip (%d) to read attributes from!", - o_i2cInfo.eepromRole ); - - /*@ - * @errortype - * @reasoncode EEPROM_INVALID_CHIP - * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE - * @moduleid EEPROM_READATTRIBUTES - * @userdata1 EEPROM Chip - * @userdata2 HUID of target - * @devdesc Invalid EEPROM chip to access - */ - err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, - EEPROM_READATTRIBUTES, - EEPROM_INVALID_CHIP, - o_i2cInfo.eepromRole, - TARGETING::get_huid(i_target), - true /*Add HB SW Callout*/ ); - - err->collectTrace( EEPROM_COMP_NAME ); - - break; - } - - // Check if Attribute Data was found - if( fail_reading_attribute == true ) - { - TRACFCOMP( g_trac_eeprom, - ERR_MRK"eepromReadAttributes() - ERROR reading " - "attributes for eeprom role %d!", - o_i2cInfo.eepromRole ); - - /*@ - * @errortype - * @reasoncode EEPROM_ATTR_INFO_NOT_FOUND - * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE - * @moduleid EEPROM_READATTRIBUTES - * @userdata1 HUID of target - * @userdata2 EEPROM chip - * @devdesc EEPROM attribute was not found - */ - err = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_UNRECOVERABLE, - EEPROM_READATTRIBUTES, - EEPROM_ATTR_INFO_NOT_FOUND, - TARGETING::get_huid(i_target), - o_i2cInfo.eepromRole); - - // Could be FSP or HB code's fault - err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, - HWAS::SRCI_PRIORITY_MED); - err->addProcedureCallout(HWAS::EPUB_PRC_SP_CODE, - HWAS::SRCI_PRIORITY_MED); - - err->collectTrace( EEPROM_COMP_NAME ); - - break; - - } - - // Successful reading of Attribute, so extract the data - o_i2cInfo.port = eepromData.port; - o_i2cInfo.devAddr = eepromData.devAddr; - o_i2cInfo.engine = eepromData.engine; - o_i2cInfo.i2cMasterPath = eepromData.i2cMasterPath; - o_i2cInfo.writePageSize = eepromData.writePageSize; - o_i2cInfo.devSize_KB = eepromData.maxMemorySizeKB; - o_i2cInfo.chipCount = eepromData.chipCount; - o_i2cInfo.writeCycleTime = eepromData.writeCycleTime; - o_i2cInfo.i2cMuxBusSelector = eepromData.i2cMuxBusSelector; - o_i2cInfo.i2cMuxPath = eepromData.i2cMuxPath; - - // Convert attribute info to eeprom_addr_size_t enum - if ( eepromData.byteAddrOffset == 0x3 ) - { - o_i2cInfo.addrSize = ONE_BYTE_ADDR; - } - else if ( eepromData.byteAddrOffset == 0x2 ) - { - o_i2cInfo.addrSize = TWO_BYTE_ADDR; - } - else if ( eepromData.byteAddrOffset == 0x1 ) - { - o_i2cInfo.addrSize = ONE_BYTE_ADDR_PAGESELECT; - } - else if ( eepromData.byteAddrOffset == 0x0 ) - { - o_i2cInfo.addrSize = ZERO_BYTE_ADDR; - } - else - { - TRACFCOMP( g_trac_eeprom, - ERR_MRK"eepromReadAttributes() - INVALID ADDRESS " - "OFFSET SIZE %d!", - o_i2cInfo.addrSize ); - - /*@ - * @errortype - * @reasoncode EEPROM_INVALID_ADDR_OFFSET_SIZE - * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE - * @moduleid EEPROM_READATTRIBUTES - * @userdata1 HUID of target - * @userdata2 Address Offset Size - * @devdesc Invalid address offset size - */ - err = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_UNRECOVERABLE, - EEPROM_READATTRIBUTES, - EEPROM_INVALID_ADDR_OFFSET_SIZE, - TARGETING::get_huid(i_target), - o_i2cInfo.addrSize, - true /*Add HB SW Callout*/ ); - - err->collectTrace( EEPROM_COMP_NAME ); - - break; - - } - - } while( 0 ); - - TRACUCOMP(g_trac_eeprom,"eepromReadAttributes() tgt=0x%X, %d/%d/0x%X " - "wpw=0x%X, dsKb=0x%X, chpCnt=%d, aS=%d (%d)", - TARGETING::get_huid(i_target), - o_i2cInfo.port, o_i2cInfo.engine, o_i2cInfo.devAddr, - o_i2cInfo.writePageSize, o_i2cInfo.devSize_KB, - o_i2cInfo.chipCount, o_i2cInfo.addrSize, - eepromData.byteAddrOffset); - - - - // Printing mux info separately, if combined, nothing is displayed - char* l_muxPath = o_i2cInfo.i2cMuxPath.toString(); - TRACFCOMP(g_trac_eeprom, "eepromReadAttributes(): " - "muxSelector=0x%X, muxPath=%s", - o_i2cInfo.i2cMuxBusSelector, - l_muxPath); - free(l_muxPath); - l_muxPath = nullptr; - - TRACDCOMP( g_trac_eeprom, - EXIT_MRK"eepromReadAttributes()" ); - - return err; -} // end eepromReadAttributes - - -// ------------------------------------------------------------------ -// eepromGetI2CMasterTarget -// ------------------------------------------------------------------ -errlHndl_t eepromGetI2CMasterTarget ( TARGETING::Target * i_target, - eeprom_addr_t i_i2cInfo, - TARGETING::Target * &o_target ) -{ - errlHndl_t err = NULL; - o_target = NULL; - - TRACDCOMP( g_trac_eeprom, - ENTER_MRK"eepromGetI2CMasterTarget()" ); - - do - { - TARGETING::TargetService& tS = TARGETING::targetService(); - - // The path from i_target to its I2C Master was read from the - // attribute via eepromReadAttributes() and passed to this function - // in i_i2cInfo.i2cMasterPath - - // check that the path exists - bool exists = false; - tS.exists( i_i2cInfo.i2cMasterPath, - exists ); - - if( !exists ) - { - TRACFCOMP( g_trac_eeprom, - ERR_MRK"eepromGetI2CMasterTarget() - " - "i2cMasterPath attribute path doesn't exist!" ); - - // Compress the entity path - uint64_t l_epCompressed = 0; - for( uint32_t i = 0; i < i_i2cInfo.i2cMasterPath.size(); i++ ) - { - // Path element: type:8 instance:8 - l_epCompressed |= - i_i2cInfo.i2cMasterPath[i].type << (16*(3-i)); - l_epCompressed |= - i_i2cInfo.i2cMasterPath[i].instance << ((16*(3-i))-8); - - // Can only fit 4 path elements into 64 bits - if ( i == 3 ) - { - break; - } - } - - /*@ - * @errortype - * @reasoncode EEPROM_I2C_MASTER_PATH_ERROR - * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE - * @moduleid EEPROM_GETI2CMASTERTARGET - * @userdata1[00:31] Attribute Chip Type Enum - * @userdata1[32:63] HUID of target - * @userdata2 Compressed Entity Path - * @devdesc I2C master entity path doesn't exist. - */ - err = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_UNRECOVERABLE, - EEPROM_GETI2CMASTERTARGET, - EEPROM_I2C_MASTER_PATH_ERROR, - TWO_UINT32_TO_UINT64( - i_i2cInfo.eepromRole, - TARGETING::get_huid(i_target) ), - l_epCompressed, - true /*Add HB SW Callout*/ ); - - err->collectTrace( EEPROM_COMP_NAME ); - - char* l_masterPath = i_i2cInfo.i2cMasterPath.toString(); - ERRORLOG::ErrlUserDetailsString(l_masterPath).addToLog(err); - free(l_masterPath); - l_masterPath = nullptr; - - break; - } - - // Since it exists, convert to a target - o_target = tS.toTarget( i_i2cInfo.i2cMasterPath ); - - if( NULL == o_target ) - { - TRACFCOMP( g_trac_eeprom, - ERR_MRK"eepromGetI2CMasterTarget() - I2C Master " - "Path target was NULL!" ); - - // Compress the entity path - uint64_t l_epCompressed = 0; - for( uint32_t i = 0; i < i_i2cInfo.i2cMasterPath.size(); i++ ) - { - // Path element: type:8 instance:8 - l_epCompressed |= - i_i2cInfo.i2cMasterPath[i].type << (16*(3-i)); - l_epCompressed |= - i_i2cInfo.i2cMasterPath[i].instance << ((16*(3-i))-8); - - // Can only fit 4 path elements into 64 bits - if ( i == 3 ) - { - break; - } - } - - /*@ - * @errortype - * @reasoncode EEPROM_TARGET_NULL - * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE - * @moduleid EEPROM_GETI2CMASTERTARGET - * @userdata1[00:31] Attribute Chip Type Enum - * @userdata1[32:63] HUID of target - * @userdata2 Compressed Entity Path - * @devdesc I2C master path target is null. - */ - err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - EEPROM_GETI2CMASTERTARGET, - EEPROM_TARGET_NULL, - TWO_UINT32_TO_UINT64( - i_i2cInfo.eepromRole, - TARGETING::get_huid(i_target) ), - l_epCompressed, - true /*Add HB SW Callout*/ ); - - err->collectTrace( EEPROM_COMP_NAME ); - - char* l_masterPath = i_i2cInfo.i2cMasterPath.toString(); - ERRORLOG::ErrlUserDetailsString(l_masterPath).addToLog(err); - free(l_masterPath); - l_masterPath = nullptr; - - break; - } - - } while( 0 ); - - TRACDCOMP( g_trac_eeprom, - EXIT_MRK"eepromGetI2CMasterTarget()" ); + EXIT_MRK"eepromPerformOp() - %s", + ((NULL == err) ? "No Error" : "With Error") ); return err; -} // end eepromGetI2CMasterTarget - - -/** - * @brief Compare predicate for EepromInfo_t - */ -class isSameEeprom -{ - public: - isSameEeprom( EepromInfo_t& i_first ) - : iv_first(i_first) - {} - - bool operator()( EepromInfo_t& i_second ) - { - return( (iv_first.i2cMaster == i_second.i2cMaster) - && (iv_first.engine == i_second.engine) - && (iv_first.port == i_second.port) - && (iv_first.devAddr == i_second.devAddr) ); - } - private: - EepromInfo_t& iv_first; -}; - -/** - * @brief Add any new EEPROMs associated with this target - * to the list - * @param[in] i_list : list of previously discovered EEPROMs - * @param[out] i_targ : owner of EEPROMs to add - */ -void add_to_list( std::list<EepromInfo_t>& i_list, - TARGETING::Target* i_targ ) -{ - TRACFCOMP(g_trac_eeprom,"Targ %.8X",TARGETING::get_huid(i_targ)); - - // try all defined types of EEPROMs - for( eeprom_chip_types_t eep_type = FIRST_CHIP_TYPE; - eep_type < LAST_CHIP_TYPE; - eep_type = static_cast<eeprom_chip_types_t>(eep_type+1) ) - { - bool found_eep = false; - TARGETING::EepromVpdPrimaryInfo eepromData; - - switch( eep_type ) - { - case VPD_PRIMARY: - if( i_targ-> - tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO> - ( eepromData ) ) - - { - found_eep = true; - } - break; - - case VPD_BACKUP: - if( i_targ-> - tryGetAttr<TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO> - ( reinterpret_cast< - TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO_type&> - ( eepromData) ) ) - { - found_eep = true; - } - break; - - case SBE_PRIMARY: - if( i_targ-> - tryGetAttr<TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO> - ( reinterpret_cast< - TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO_type&> - ( eepromData) ) ) - { - found_eep = true; - } - break; - - case SBE_BACKUP: - if( i_targ-> - tryGetAttr<TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO> - ( reinterpret_cast< - TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO_type&> - ( eepromData) ) ) - { - found_eep = true; - } - break; - - case LAST_CHIP_TYPE: - //only included to catch additional types later on - found_eep = false; - break; - } - - if( !found_eep ) - { - TRACDCOMP(g_trac_eeprom,"eep_type=%d not found",eep_type); - //nothing to do - continue; - } - - // check that the path exists - bool exists = false; - TARGETING::targetService().exists( eepromData.i2cMasterPath, - exists ); - if( !exists ) - { - TRACDCOMP(g_trac_eeprom,"no master path"); - continue; - } - - // Since it exists, convert to a target - TARGETING::Target* i2cm = TARGETING::targetService() - .toTarget( eepromData.i2cMasterPath ); - if( NULL == i2cm ) - { - //not sure how this could happen, but just skip it - TRACDCOMP(g_trac_eeprom,"no target"); - continue; - } - - // ignore anything with junk data - TARGETING::Target * sys = NULL; - TARGETING::targetService().getTopLevelTarget( sys ); - if( i2cm == sys ) - { - TRACDCOMP(g_trac_eeprom,"sys target"); - continue; - } - - // copy all the data out - EepromInfo_t eep_info; - eep_info.i2cMaster = i2cm; - eep_info.engine = eepromData.engine; - eep_info.port = eepromData.port; - eep_info.devAddr = eepromData.devAddr; - eep_info.device = eep_type; - eep_info.assocTarg = i_targ; - eep_info.chipCount = eepromData.chipCount; - eep_info.sizeKB = eepromData.maxMemorySizeKB; - eep_info.addrBytes = eepromData.byteAddrOffset; - //one more lookup for the speed - TARGETING::ATTR_I2C_BUS_SPEED_ARRAY_type speeds; - if( i2cm->tryGetAttr<TARGETING::ATTR_I2C_BUS_SPEED_ARRAY> - (speeds) ) - { - if( (eep_info.engine > I2C_BUS_MAX_ENGINE(speeds)) - || (eep_info.port > I2C_BUS_MAX_PORT(speeds)) ) - { - TRACDCOMP(g_trac_eeprom,"bad engine/port"); - continue; - } - eep_info.busFreq = speeds[eep_info.engine][eep_info.port]; - eep_info.busFreq *= 1000; //convert KHz->Hz - } - else - { - TRACDCOMP(g_trac_eeprom,"eep_type=%d, Speed=0",eep_type); - continue; - } - - // check if the eeprom is already in our list - std::list<EepromInfo_t>::iterator oldeep = - find_if( i_list.begin(), i_list.end(), - isSameEeprom(eep_info) ); - if( oldeep == i_list.end() ) - { - // didn't find it in our list so stick it into the output list - i_list.push_back(eep_info); - TRACFCOMP(g_trac_eeprom,"--Adding i2cm=%.8X, type=%d, eng=%d, port=%d, addr=%.2X for %.8X", TARGETING::get_huid(i2cm),eep_type,eepromData.engine,eepromData.port, eep_info.devAddr, TARGETING::get_huid(eep_info.assocTarg)); - } - else - { - TRACFCOMP(g_trac_eeprom,"--Skipping duplicate i2cm=%.8X, type=%d, eng=%d, port=%d, addr=%.2X for %.8X", TARGETING::get_huid(i2cm),eep_type,eepromData.engine,eepromData.port, eep_info.devAddr, TARGETING::get_huid(eep_info.assocTarg)); - } - } -} - -/** - * @brief Return a set of information related to every unique - * EEPROM in the system - */ -void getEEPROMs( std::list<EepromInfo_t>& o_info ) -{ - TRACFCOMP(g_trac_eeprom,">>getEEPROMs()"); - - // We only want to have a single entry in our list per - // physical EEPROM. Since multiple targets could be - // using the same EEPROM, we need to have a hierarchy - // of importance. - // node/planar > proc > membuf > dimm - - // predicate to only look for this that are actually there - TARGETING::PredicateHwas isPresent; - isPresent.reset().poweredOn(true).present(true); +} // end eepromPerformOp - // #1 - Nodes - TARGETING::PredicateCTM nodes( TARGETING::CLASS_ENC, - TARGETING::TYPE_NODE, - TARGETING::MODEL_NA ); - TARGETING::PredicatePostfixExpr l_nodeFilter; - l_nodeFilter.push(&isPresent).push(&nodes).And(); - TARGETING::TargetRangeFilter node_itr( TARGETING::targetService().begin(), - TARGETING::targetService().end(), - &l_nodeFilter ); - for( ; node_itr; ++node_itr ) - { - add_to_list( o_info, *node_itr ); - } +// Register the perform Op with the routing code for Procs. +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::EEPROM, + TARGETING::TYPE_PROC, + eepromPerformOp ); - // #2 - Procs - TARGETING::PredicateCTM procs( TARGETING::CLASS_CHIP, - TARGETING::TYPE_PROC, - TARGETING::MODEL_NA ); - TARGETING::PredicatePostfixExpr l_procFilter; - l_procFilter.push(&isPresent).push(&procs).And(); - TARGETING::TargetRangeFilter proc_itr( TARGETING::targetService().begin(), - TARGETING::targetService().end(), - &l_procFilter ); - for( ; proc_itr; ++proc_itr ) - { - add_to_list( o_info, *proc_itr ); - } +// Register the perform Op with the routing code for DIMMs. +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::EEPROM, + TARGETING::TYPE_DIMM, + eepromPerformOp ); - // #3 - Membufs - TARGETING::PredicateCTM membs( TARGETING::CLASS_CHIP, - TARGETING::TYPE_MEMBUF, - TARGETING::MODEL_NA ); - TARGETING::PredicatePostfixExpr l_membFilter; - l_membFilter.push(&isPresent).push(&membs).And(); - TARGETING::TargetRangeFilter memb_itr( TARGETING::targetService().begin(), - TARGETING::targetService().end(), - &l_membFilter ); - for( ; memb_itr; ++memb_itr ) - { - add_to_list( o_info, *memb_itr ); - } +// Register the perform Op with the routing code for Memory Buffers. +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::EEPROM, + TARGETING::TYPE_MEMBUF, + eepromPerformOp ); - // #4 - DIMMs - TARGETING::PredicateCTM dimms( TARGETING::CLASS_LOGICAL_CARD, - TARGETING::TYPE_DIMM, - TARGETING::MODEL_NA ); - TARGETING::PredicatePostfixExpr l_dimmFilter; - l_dimmFilter.push(&isPresent).push(&dimms).And(); - TARGETING::TargetRangeFilter dimm_itr( TARGETING::targetService().begin(), - TARGETING::targetService().end(), - &l_dimmFilter ); - for( ; dimm_itr; ++dimm_itr ) - { - #ifdef CONFIG_NVDIMM - // Skip if this is an NVDIMM as this will get added later - if (TARGETING::isNVDIMM( *dimm_itr )) - continue; - #endif - add_to_list( o_info, *dimm_itr ); - } +// Register the perform Op with the routing code for Nodes. +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::EEPROM, + TARGETING::TYPE_NODE, + eepromPerformOp ); - TRACFCOMP(g_trac_eeprom,"<<getEEPROMs()"); -} +// Register the perform Op with the routing code for MCS chiplets. +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::EEPROM, + TARGETING::TYPE_MCS, + eepromPerformOp ); +// Register the perform Op with the routing code for Open-Capi Memory Buffer Chips. +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::EEPROM, + TARGETING::TYPE_OCMB_CHIP, + eepromPerformOp ); } // end namespace EEPROM diff --git a/src/usr/i2c/eepromdd_hardware.C b/src/usr/i2c/eepromdd_hardware.C new file mode 100644 index 000000000..351ca549a --- /dev/null +++ b/src/usr/i2c/eepromdd_hardware.C @@ -0,0 +1,1364 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/i2c/eepromdd_hardware.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2019 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include "eepromdd_hardware.H" +#include <sys/time.h> +#include "errlud_i2c.H" +#include <i2c/eepromif.H> +#include <i2c/i2cif.H> +#include <errl/errlmanager.H> +#include <i2c/i2creasoncodes.H> +#include <i2c/eepromddreasoncodes.H> +#include <errl/errludstring.H> +#include <errl/errludtarget.H> + +extern trace_desc_t* g_trac_eeprom; + +// ---------------------------------------------- +// Globals +// ---------------------------------------------- +mutex_t g_eepromMutex = MUTEX_INITIALIZER; + +// Easy macro replace for unit testing +//#define TRACUCOMP(args...) TRACFCOMP(args) +#define TRACUCOMP(args...) + +namespace +{ + +// ------------------------------------------------------------------ +// errorIsRetryable +// ------------------------------------------------------------------ +static bool errorIsRetryable(uint16_t reasonCode) +{ + return reasonCode == I2C::I2C_NACK_ONLY_FOUND || + reasonCode == I2C::I2C_ARBITRATION_LOST_ONLY_FOUND; +} + +} + +namespace EEPROM +{ + +errlHndl_t eepromPerformOpHW(DeviceFW::OperationType i_opType, + TARGETING::Target * i_target, + void * io_buffer, + size_t & io_buflen, + eeprom_addr_t & io_i2cInfo) +{ +#ifdef __HOSTBOOT_RUNTIME + // At runtime the OCC sensor cache will need to be disabled to avoid I2C + // collisions. This bool indicates the sensor cache was enabled but is + // now disabled and needs to be re-enabled when the eeprom op completes. + bool scacDisabled = false; +#endif //__HOSTBOOT_RUNTIME + TARGETING::Target * i2cMasterTarget = nullptr; + void * l_pBuffer = io_buffer; + size_t l_currentOpLen = io_buflen; + size_t l_remainingOpLen = io_buflen; + errlHndl_t err = nullptr; + + do + { + // Read Attributes needed to complete the operation + err = eepromReadAttributes( i_target, + io_i2cInfo ); + + if( err ) + { + break; + } + + size_t l_snglChipSize = (io_i2cInfo.devSize_KB * KILOBYTE) + / io_i2cInfo.chipCount; + + // Check to see if we need to find a new target for + // the I2C Master + err = eepromGetI2CMasterTarget( i_target, + io_i2cInfo, + i2cMasterTarget ); + + if( err ) + { + break; + } + + // Check that the offset + data length is less than device max size + if ( ( io_i2cInfo.offset + io_buflen ) > + ( io_i2cInfo.devSize_KB * KILOBYTE ) ) + { + TRACFCOMP( g_trac_eeprom, + ERR_MRK"eepromPerformOp(): Device Overflow! " + "C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X " + "devSizeKB=0x%X", io_i2cInfo.eepromRole, io_i2cInfo.engine, + io_i2cInfo.port, io_i2cInfo.devAddr, io_i2cInfo.offset, + io_buflen, io_i2cInfo.devSize_KB); + + + /*@ + * @errortype + * @reasoncode EEPROM_OVERFLOW_ERROR + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid EEPROM_PERFORM_OP + * @userdata1[0:31] Offset + * @userdata1[32:63] Buffer Length + * @userdata2 Device Max Size (in KB) + * @devdesc I2C Buffer Length + Offset > Max Size + * @custdesc A problem occurred during the IPL of the + * system: I2C buffer offset is too large. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_PERFORM_OP, + EEPROM_OVERFLOW_ERROR, + TWO_UINT32_TO_UINT64( + io_i2cInfo.offset, + io_buflen ), + io_i2cInfo.devSize_KB, + true /*Add HB SW Callout*/ ); + + err->collectTrace( EEPROM_COMP_NAME ); + + break; + } + + // Adjust offset and devAddr to the correct starting chip + while( io_i2cInfo.offset >= l_snglChipSize ) + { + io_i2cInfo.offset -= l_snglChipSize; + io_i2cInfo.devAddr += EEPROM_DEVADDR_INC; + } + + // Keep first op length within a chip + if( ( io_i2cInfo.offset + io_buflen ) > l_snglChipSize ) + { + l_currentOpLen = l_snglChipSize - io_i2cInfo.offset; + } + + TRACFCOMP( g_trac_eeprom, + "eepromPerformOp(): i_opType=%d " + "C-e/p/dA=%d-%d/%d/0x%X, offset=0x%X, len=0x%X, ", + i_opType, io_i2cInfo.eepromRole, io_i2cInfo.engine, + io_i2cInfo.port, io_i2cInfo.devAddr, io_i2cInfo.offset, io_buflen) + + TRACFCOMP (g_trac_eeprom, + "eepromPerformOp(): snglChipKB=0x%X, chipCount=0x%X, devSizeKB=0x%X", + l_snglChipSize, io_i2cInfo.chipCount, io_i2cInfo.devSize_KB); + + // Printing mux info separately, if combined, nothing is displayed + char* l_muxPath = io_i2cInfo.i2cMuxPath.toString(); + TRACFCOMP(g_trac_eeprom, "eepromPerformOp(): " + "muxSelector=0x%X, muxPath=%s", + io_i2cInfo.i2cMuxBusSelector, + l_muxPath); + free(l_muxPath); + l_muxPath = nullptr; + +#ifdef __HOSTBOOT_RUNTIME + // Disable Sensor Cache if the I2C master target is MEMBUF + if( i2cMasterTarget->getAttr<TARGETING::ATTR_TYPE>() == + TARGETING::TYPE_MEMBUF ) + { + err = I2C::i2cDisableSensorCache(i2cMasterTarget,scacDisabled); + if ( err ) + { + break; + } + } +#endif //__HOSTBOOT_RUNTIME + + // Do the read or write + while(l_remainingOpLen > 0) + { + if( i_opType == DeviceFW::READ ) + { + err = eepromRead( i2cMasterTarget, + l_pBuffer, + l_currentOpLen, + io_i2cInfo ); + } + else if( i_opType == DeviceFW::WRITE ) + { + err = eepromWrite( i2cMasterTarget, + l_pBuffer, + l_currentOpLen, + io_i2cInfo ); + } + else + { + TRACFCOMP( g_trac_eeprom, + ERR_MRK"eepromPerformOp(): " + "Invalid EEPROM Operation!"); + + /*@ + * @errortype + * @reasoncode EEPROM_INVALID_OPERATION + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid EEPROM_PERFORM_OP + * @userdata1 Operation Type + * @userdata2 Chip to Access + * @devdesc Invalid operation type. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_PERFORM_OP, + EEPROM_INVALID_OPERATION, + i_opType, + io_i2cInfo.eepromRole, + true /*Add HB SW Callout*/ ); + + err->collectTrace( EEPROM_COMP_NAME ); + } + + if ( err ) + { + break; + } + + // Adjust the buffer pointer and remaining op length + l_pBuffer = (void *)(reinterpret_cast<uint64_t>(l_pBuffer) + + l_currentOpLen); + l_remainingOpLen -= l_currentOpLen; + + if( l_remainingOpLen > l_snglChipSize ) + { + // Keep next op length within a chip + l_currentOpLen = l_snglChipSize; + } + else if( l_remainingOpLen > 0 ) + { + // Set next op length to what is left to do + l_currentOpLen = l_remainingOpLen; + } + else + { + // Break if there is nothing left to do + break; + } + + // Prepare the address at the start of next EEPROM + io_i2cInfo.offset = 0; + io_i2cInfo.devAddr += EEPROM_DEVADDR_INC; + } // Do the read or write + } while( 0 ); + +#ifdef __HOSTBOOT_RUNTIME + // Re-enable sensor cache if it was disabled before the eeprom op and + // the I2C master target is MEMBUF + if( scacDisabled && + (i2cMasterTarget->getAttr<TARGETING::ATTR_TYPE>() == TARGETING::TYPE_MEMBUF) ) + { + errlHndl_t tmp_err = NULL; + + tmp_err = I2C::i2cEnableSensorCache(i2cMasterTarget); + + if( err && tmp_err) + { + delete tmp_err; + TRACFCOMP(g_trac_eeprom, + ERR_MRK" Enable Sensor Cache failed for HUID=0x%.8X", + TARGETING::get_huid(i2cMasterTarget)); + } + else if(tmp_err) + { + err = tmp_err; + } + } +#endif //__HOSTBOOT_RUNTIME + + // If there is an error, add parameter info to log + if ( err != NULL ) + { + EEPROM::UdEepromParms( i_opType, + i_target, + io_buflen, + io_i2cInfo ) + .addToLog(err); + } + + return err; +} + +// ------------------------------------------------------------------ +// eepromPageOp +// ------------------------------------------------------------------ +errlHndl_t eepromPageOp( TARGETING::Target * i_target, + bool i_switchPage, + bool i_lockMutex, + bool & io_pageLocked, + uint8_t i_desiredPage, + const eeprom_addr_t & i_i2cInfo ) +{ + TRACUCOMP(g_trac_eeprom, + ENTER_MRK"eepromPageOp()"); + + errlHndl_t l_err = NULL; + size_t l_placeHolderZero = 0; + + do + { + // DDR4 requires EEPROM page to be selected before read/write operation. + // The following operation locks the EEPROM_PAGE attribute behind a + // mutex and switches all DIMMs on the I2C bus to the appropriate + // page. + if( i_i2cInfo.addrSize == ONE_BYTE_ADDR_PAGESELECT ) + { + + bool l_lockPage; + if( i_switchPage ) + { + // we want to switch to the desired page + l_lockPage = true; + l_err = deviceOp( DeviceFW::WRITE, + i_target, + NULL, + l_placeHolderZero, + DEVICE_I2C_CONTROL_PAGE_OP( + i_i2cInfo.port, + i_i2cInfo.engine, + l_lockPage, + i_desiredPage, + i_lockMutex )); + + if( l_err ) + { + TRACFCOMP(g_trac_eeprom, + "eepromPageOp::Failed locking EEPROM page"); + break; + } + // if we make it this far, we successfully locked the page mutex + io_pageLocked = true; + } + else + { + // we only want to unlock the page + l_lockPage = false; + l_err = deviceOp( DeviceFW::WRITE, + i_target, + NULL, + l_placeHolderZero, + DEVICE_I2C_CONTROL_PAGE_OP( + i_i2cInfo.port, + i_i2cInfo.engine, + l_lockPage, + l_placeHolderZero, + i_lockMutex )); + + if( l_err ) + { + TRACFCOMP( g_trac_eeprom, + "eepromPageOp()::failed unlocking EEPROM page"); + break; + } + // if we make it this far, we successfully unlocked the page + io_pageLocked = false; + } + } + }while(0); + TRACUCOMP(g_trac_eeprom, + EXIT_MRK"eepromPageOp()"); + return l_err; +} + + +// ------------------------------------------------------------------ +// crossesEepromPageBoundary +// ------------------------------------------------------------------ +bool crossesEepromPageBoundary( uint64_t i_originalOffset, + size_t i_originalLen, + size_t & io_newLen, + size_t & o_pageTwoBuflen, + const eeprom_addr_t& i_i2cInfo ) +{ + bool l_boundaryCrossed = false; + size_t l_higherBound = i_originalOffset + i_originalLen; + + if( ( i_i2cInfo.addrSize == ONE_BYTE_ADDR_PAGESELECT ) && + ( ( i_originalOffset < EEPROM_PAGE_SIZE ) && + ( l_higherBound > EEPROM_PAGE_SIZE) ) ) + { + // The read/write request crosses the boundary + l_boundaryCrossed = true; + + // Calculate the new length of the page 0 buffer and the + // length of the page 1 buffer + o_pageTwoBuflen = l_higherBound - EEPROM_PAGE_SIZE; + io_newLen = i_originalLen - o_pageTwoBuflen; + } + else + { + // The read/write request does not cross the boundary. + // Update new length to be used by subsequent operations + io_newLen = i_originalLen; + o_pageTwoBuflen = 0; + } + + return l_boundaryCrossed; +} + + + +// ------------------------------------------------------------------ +// eepromRead +// ------------------------------------------------------------------ +errlHndl_t eepromRead ( TARGETING::Target * i_target, + void * o_buffer, + size_t i_buflen, + eeprom_addr_t i_i2cInfo ) +{ + errlHndl_t err = NULL; + uint8_t byteAddr[MAX_BYTE_ADDR]; + size_t byteAddrSize = 0; + bool l_pageLocked = false; + uint8_t l_desiredPage = 0; + bool l_boundaryCrossed = false; + size_t l_readBuflen = 0; + size_t l_pageTwoBuflen = 0; + + TRACUCOMP( g_trac_eeprom, + ENTER_MRK"eepromRead()" ); + + do + { + TRACUCOMP( g_trac_eeprom, + "EEPROM READ START : Chip: %02d : Offset %.2X : Len %d", + i_i2cInfo.chip, i_i2cInfo.offset, i_buflen ); + + // At maximum we want to do 1 KB reads at a time. The largest that + // the scom byte range will support is 64 KB - 1 but we will do 1 + // KB at a time to catch fails faster. This is useful when we do big + // reads when caching the eeprom to pnor. + size_t l_readLenRemaining = i_buflen; + size_t l_currentReadLen; + + // Lock to sequence operations + mutex_lock( &g_eepromMutex ); + + while( l_readLenRemaining > 0 ) + { + l_currentReadLen = l_readLenRemaining < KILOBYTE ? l_readLenRemaining : KILOBYTE; + + // Check to see if the Read operation straddles the EEPROM page + // boundary.Note this is only required for systems w/ DDR4 industry + // standard dimms. DDR4 ISDIMMS have a max of 512 bytes so we will + // never loop through this multiple times on those systems + l_boundaryCrossed = crossesEepromPageBoundary( i_i2cInfo.offset, + l_currentReadLen, + l_readBuflen, + l_pageTwoBuflen, + i_i2cInfo ); + + // Set addressing parameters + err = eepromPrepareAddress( i_target, + &byteAddr, + byteAddrSize, + l_desiredPage, + i_i2cInfo); + + if( err ) + { + TRACFCOMP(g_trac_eeprom, + ERR_MRK"eepromRead()::eepromPrepareAddress()"); + break; + } + + + // Attempt to lock page mutex + // (only important in DDR4 IS-DIMM systems) + bool l_switchPage = true; + bool l_lockMutex = true; + err = eepromPageOp( i_target, + l_switchPage, + l_lockMutex, + l_pageLocked, + l_desiredPage, + i_i2cInfo ); + + if( err ) + { + TRACFCOMP(g_trac_eeprom, + "eepromRead()::eepromPageOp()::failed locking page"); + break; + } + + // First Read. If Second read is necessary, this call will read + // everything from the original offset up to the 256th byte + err = eepromReadData( i_target, + &(reinterpret_cast<uint8_t*>(o_buffer)[i_buflen - l_readLenRemaining]), + l_readBuflen, + &byteAddr, + byteAddrSize, + i_i2cInfo ); + + i_i2cInfo.offset += l_currentReadLen; + l_readLenRemaining -= l_currentReadLen; + + if( err ) + { + TRACFCOMP(g_trac_eeprom, + "Failed reading data: original read"); + break; + } + + + // Perform the second Read if necessary. Read starts at + // begining of EEPROM page 1 (offset=0x100) and reads the + // rest of the required data. + if( l_boundaryCrossed ) + { + //Prepare the address to read at the start of EEPROM page one + i_i2cInfo.offset = EEPROM_PAGE_SIZE; // 0x100 + err = eepromPrepareAddress( i_target, + &byteAddr, + byteAddrSize, + l_desiredPage, + i_i2cInfo ); + if( err ) + { + TRACFCOMP(g_trac_eeprom, + "Error preparing address: second eeprom read"); + break; + } + + // Switch to the second EEPROM page + l_switchPage = true; + l_lockMutex = false; + err = eepromPageOp( i_target, + l_switchPage, + l_lockMutex, + l_pageLocked, + l_desiredPage, + i_i2cInfo ); + + if( err ) + { + TRACFCOMP( g_trac_eeprom, + "Failed switching to EEPROM page 1 for second read op"); + break; + } + + // Perform the second read operation + err = eepromReadData( + i_target, + &(reinterpret_cast<uint8_t*>(o_buffer)[l_readBuflen]), + l_pageTwoBuflen, + &byteAddr, + byteAddrSize, + i_i2cInfo ); + + if( err ) + { + TRACFCOMP( g_trac_eeprom, + "Failed reading data: second read"); + break; + } + } + } + + + TRACUCOMP( g_trac_eeprom, + "EEPROM READ END : Eeprom Role: %02d : Offset %.2X : Len %d : %016llx", + i_i2cInfo.eepromRole, i_i2cInfo.offset, i_buflen, + *((uint64_t*)o_buffer) ); + + } while( 0 ); + + // Unlock eeprom mutex no matter what + mutex_unlock( & g_eepromMutex ); + + // Whether we failed in the main routine or not, unlock page iff the page is locked + if( l_pageLocked ) + { + errlHndl_t l_pageOpErrl = NULL; + bool l_switchPage = false; + bool l_lockMutex = false; + l_pageOpErrl = eepromPageOp( i_target, + l_switchPage, + l_lockMutex, + l_pageLocked, + l_desiredPage, + i_i2cInfo ); + if( l_pageOpErrl ) + { + TRACFCOMP(g_trac_eeprom, + "eepromRead()::Failed unlocking page"); + errlCommit(l_pageOpErrl, I2C_COMP_ID); + } + + } + + TRACUCOMP( g_trac_eeprom, + EXIT_MRK"eepromRead()" ); + + return err; +} // end eepromRead + + +// ------------------------------------------------------------------ +// eepromReadData +// ------------------------------------------------------------------ +errlHndl_t eepromReadData( TARGETING::Target * i_target, + void * o_buffer, + size_t i_buflen, + void * i_byteAddress, + size_t i_byteAddressSize, + eeprom_addr_t i_i2cInfo ) +{ + errlHndl_t l_err = NULL; + errlHndl_t err_retryable = NULL; + + TRACUCOMP(g_trac_eeprom, + ENTER_MRK"eepromReadData()"); + do + { + /************************************************************/ + /* Attempt read multiple times ONLY on retryable fails */ + /************************************************************/ + for (uint8_t retry = 0; + retry <= EEPROM_MAX_RETRIES; + retry++) + { + + // Only write the byte address if we have data to write + if( 0 != i_byteAddressSize ) + { + // Use the I2C MUX OFFSET Interface for the READ + l_err = deviceOp( DeviceFW::READ, + i_target, + o_buffer, + i_buflen, + DEVICE_I2C_ADDRESS_OFFSET( + i_i2cInfo.port, + i_i2cInfo.engine, + i_i2cInfo.devAddr, + i_byteAddressSize, + reinterpret_cast<uint8_t*>(i_byteAddress), + i_i2cInfo.i2cMuxBusSelector, + &(i_i2cInfo.i2cMuxPath))); + + if( l_err ) + { + TRACFCOMP(g_trac_eeprom, + ERR_MRK"eepromReadData(): I2C Read-Offset failed on " + "%d/%d/0x%X aS=%d", + i_i2cInfo.port, i_i2cInfo.engine, + i_i2cInfo.devAddr, i_byteAddressSize); + TRACFBIN(g_trac_eeprom, "i_byteAddress[]", + i_byteAddress, i_byteAddressSize); + + // Don't break here -- error handled below + } + } + else + { + // Do the actual read via I2C + l_err = deviceOp( DeviceFW::READ, + i_target, + o_buffer, + i_buflen, + DEVICE_I2C_ADDRESS( + i_i2cInfo.port, + i_i2cInfo.engine, + i_i2cInfo.devAddr, + i_i2cInfo.i2cMuxBusSelector, + &(i_i2cInfo.i2cMuxPath) ) ); + + if( l_err ) + { + TRACFCOMP(g_trac_eeprom, + ERR_MRK"eepromReadData(): I2C Read failed on " + "%d/%d/0x%0X", i_i2cInfo.port, i_i2cInfo.engine, + i_i2cInfo.devAddr); + + // Don't break here -- error handled below + } + } + + if ( l_err == NULL ) + { + // Operation completed successfully + // break from retry loop + break; + } + else if ( !errorIsRetryable( l_err->reasonCode() ) ) + { + // Only retry on errorIsRetryable() failures: break from retry loop + TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): Non-Nack " + "Error: rc=0x%X, tgt=0x%X, No Retry (retry=%d)", + l_err->reasonCode(), + TARGETING::get_huid(i_target), retry); + + l_err->collectTrace(EEPROM_COMP_NAME); + + // break from retry loop + break; + } + else // Handle retryable error + { + // If op will be attempted again: save log and continue + if ( retry < EEPROM_MAX_RETRIES ) + { + // Only save original retryable error + if ( err_retryable == NULL ) + { + // Save original retryable error + err_retryable = l_err; + + TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): " + "Retryable Error rc=0x%X, eid=0x%X, tgt=0x%X, " + "retry/MAX=%d/%d. Save error and retry", + err_retryable->reasonCode(), + err_retryable->eid(), + TARGETING::get_huid(i_target), + retry, EEPROM_MAX_RETRIES); + + err_retryable->collectTrace(EEPROM_COMP_NAME); + } + else + { + // Add data to original retryable error + TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): " + "Another Retryable Error rc=0x%X, eid=0x%X " + "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. " + "Delete error and retry", + l_err->reasonCode(), l_err->eid(), l_err->plid(), + TARGETING::get_huid(i_target), + retry, EEPROM_MAX_RETRIES); + + ERRORLOG::ErrlUserDetailsString( + "Another Retryable ERROR found") + .addToLog(err_retryable); + + // Delete this new retryable error + delete l_err; + l_err = NULL; + } + + // continue to retry + continue; + } + else // no more retries: trace and break + { + TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): " + "Error rc=0x%X, eid=%d, tgt=0x%X. No More " + "Retries (retry/MAX=%d/%d). Returning Error", + l_err->reasonCode(), l_err->eid(), + TARGETING::get_huid(i_target), + retry, EEPROM_MAX_RETRIES); + + l_err->collectTrace(EEPROM_COMP_NAME); + + // break from retry loop + break; + } + } + + } // end of retry loop + + // Handle saved retryable error, if any + if (err_retryable) + { + if (l_err) + { + // commit original retryable error with new err PLID + err_retryable->plid(l_err->plid()); + TRACFCOMP(g_trac_eeprom, "eepromReadData(): Committing saved retryable " + "l_err eid=0x%X with plid of returned err: 0x%X", + err_retryable->eid(), err_retryable->plid()); + + ERRORLOG::ErrlUserDetailsTarget(i_target) + .addToLog(err_retryable); + + errlCommit(err_retryable, EEPROM_COMP_ID); + } + else + { + // Since we eventually succeeded, delete original retryable error + TRACFCOMP(g_trac_eeprom, "eepromReadData(): Op successful, " + "deleting saved retryable err eid=0x%X, plid=0x%X", + err_retryable->eid(), err_retryable->plid()); + + delete err_retryable; + err_retryable = NULL; + } + } + + }while( 0 ); + + TRACUCOMP(g_trac_eeprom, + EXIT_MRK"eepromReadData"); + return l_err; +} + + + +// ------------------------------------------------------------------ +// eepromWrite +// ------------------------------------------------------------------ +errlHndl_t eepromWrite ( TARGETING::Target * i_target, + void * io_buffer, + size_t & io_buflen, + eeprom_addr_t i_i2cInfo ) +{ + errlHndl_t err = NULL; + uint8_t l_desiredPage = 0; + uint8_t l_originalPage = 0; + uint8_t byteAddr[MAX_BYTE_ADDR]; + size_t byteAddrSize = 0; + uint8_t * newBuffer = NULL; + bool needFree = false; + bool unlock = false; + bool l_pageLocked = false; + uint32_t data_left = 0; + uint32_t diff_wps = 0; + size_t l_writeBuflen = 0; + size_t l_bytesIntoSecondPage = 0; + + TRACDCOMP( g_trac_eeprom, + ENTER_MRK"eepromWrite()" ); + + do + { + TRACUCOMP( g_trac_eeprom, + "EEPROM WRITE START : Eeprom Role : %02d : Offset %.2X : Len %d : %016llx", + i_i2cInfo.eepromRole, i_i2cInfo.offset, io_buflen, + *((uint64_t*)io_buffer) ); + + + // Prepare address parameters + err = eepromPrepareAddress( i_target, + &byteAddr, + byteAddrSize, + l_desiredPage, + i_i2cInfo); + + if( err ) + { + TRACFCOMP(g_trac_eeprom, + ERR_MRK"eepromWrite()::eepromPrepareAddress()"); + break; + } + + // Save original Page + l_originalPage = l_desiredPage; + // Attempt to lock page mutex + bool l_switchPage = true; // true: Lock and switch page + // false: Just unlock page + bool l_lockMutex = true; // true: Lock mutex + // false: Skip locking mutex step + err = eepromPageOp( i_target, + l_switchPage, + l_lockMutex, + l_pageLocked, + l_desiredPage, + i_i2cInfo ); + + if( err ) + { + TRACFCOMP(g_trac_eeprom, + "eepromWrite()::Failed locking EEPROM page"); + break; + } + + // Check for writePageSize of zero + if ( i_i2cInfo.writePageSize == 0 ) + { + TRACFCOMP( g_trac_eeprom, + ERR_MRK"eepromWrite(): writePageSize is 0!"); + + /*@ + * @errortype + * @reasoncode EEPROM_I2C_WRITE_PAGE_SIZE_ZERO + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid EEPROM_WRITE + * @userdata1 HUID of target + * @userdata2 Chip to Access + * @devdesc I2C write page size is zero. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_WRITE, + EEPROM_I2C_WRITE_PAGE_SIZE_ZERO, + TARGETING::get_huid(i_target), + i_i2cInfo.eepromRole, + true /*Add HB SW Callout*/ ); + + err->collectTrace( EEPROM_COMP_NAME ); + + break; + } + + // EEPROM devices have write page boundaries, so when necessary + // need to split up command into multiple write operations + + // Setup a max-size buffer of writePageSize + size_t newBufLen = i_i2cInfo.writePageSize; + newBuffer = static_cast<uint8_t*>(malloc( newBufLen )); + needFree = true; + + // Point a uint8_t ptr at io_buffer for array addressing below + uint8_t * l_data_ptr = reinterpret_cast<uint8_t*>(io_buffer); + + // Lock for operation sequencing + mutex_lock( &g_eepromMutex ); + unlock = true; + + // variables to store different amount of data length + size_t loop_data_length = 0; + size_t total_bytes_written = 0; + + while( total_bytes_written < io_buflen ) + { + // Determine how much data can be written in this loop + // Can't go over a writePageSize boundary + + // Total data left to write + data_left = io_buflen - total_bytes_written; + + // Difference to next writePageSize boundary + diff_wps = i_i2cInfo.writePageSize - + (i_i2cInfo.offset % i_i2cInfo.writePageSize); + + // Take the lesser of the 2 options + loop_data_length = (data_left < diff_wps ) ? data_left : diff_wps; + + // Add the data the user wanted to write + memcpy( newBuffer, + &l_data_ptr[total_bytes_written], + loop_data_length ); + + + + // Check if loop_data_length crosses the EEPROM page boundary + crossesEepromPageBoundary( i_i2cInfo.offset, + loop_data_length, + l_writeBuflen, + l_bytesIntoSecondPage, + i_i2cInfo ); + + // Setup offset/address parms + err = eepromPrepareAddress( i_target, + &byteAddr, + byteAddrSize, + l_desiredPage, + i_i2cInfo ); + + + if( err ) + { + TRACFCOMP(g_trac_eeprom, + ERR_MRK"eepromWrite::eepromPrepareAddress()::loop version"); + break; + } + + + + // if desired page has changed mid-request, switch to correct page + if( l_desiredPage != l_originalPage ) + { + l_switchPage = true; + l_lockMutex = false; + err = eepromPageOp( i_target, + l_switchPage, + l_lockMutex, + l_pageLocked, + l_desiredPage, + i_i2cInfo ); + if( err ) + { + TRACFCOMP( g_trac_eeprom, + "Failed switching to new EEPROM page!"); + break; + } + l_originalPage = l_desiredPage; + } + + TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop: %d/%d/0x%X " + "writeBuflen=%d, offset=0x%X, bAS=%d, diffs=%d/%d", + i_i2cInfo.port, i_i2cInfo.engine, i_i2cInfo.devAddr, + l_writeBuflen, i_i2cInfo.offset, byteAddrSize, + data_left, diff_wps); + + // Perform the requested write operation + err = eepromWriteData( i_target, + newBuffer, + l_writeBuflen, + &byteAddr, + byteAddrSize, + i_i2cInfo ); + + if ( err ) + { + // Can't assume that anything was written if + // there was an error, so no update to total_bytes_written + // for this loop + TRACFCOMP(g_trac_eeprom, + "Failed writing data: original eeprom write"); + break; + } + + // Wait for EEPROM to write data to its internal memory + // i_i2cInfo.writeCycleTime value in milliseconds + nanosleep( 0, i_i2cInfo.writeCycleTime * NS_PER_MSEC ); + + // Update how much data was written + total_bytes_written += l_writeBuflen; + + // Update offset + i_i2cInfo.offset += l_writeBuflen; + + TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop End: " + "writeBuflen=%d, offset=0x%X, t_b_w=%d, io_buflen=%d", + l_writeBuflen, i_i2cInfo.offset, + total_bytes_written, io_buflen); + } // end of write for-loop + + // Release mutex lock + mutex_unlock( &g_eepromMutex ); + unlock = false; + + + // Set how much data was actually written + io_buflen = total_bytes_written; + + + TRACSCOMP( g_trac_eeprom, + "EEPROM WRITE END : Eeprom Role : %02d : Offset %.2X : Len %d", + i_i2cInfo.eepromRole, i_i2cInfo.offset, io_buflen ); + } while( 0 ); + + // Free memory + if( needFree ) + { + free( newBuffer ); + } + + // Catch it if we break out early. + if( unlock ) + { + mutex_unlock( & g_eepromMutex ); + } + + + // Whether we failed in the main routine or not, unlock the page iff it is already + // locked + if( l_pageLocked ) + { + errlHndl_t l_pageOpErrl = NULL; + + bool l_switchPage = false; + bool l_lockMutex = false; + l_pageOpErrl = eepromPageOp( i_target, + l_switchPage, + l_lockMutex, + l_pageLocked, + l_desiredPage, + i_i2cInfo ); + if( l_pageOpErrl ) + { + TRACFCOMP(g_trac_eeprom, + "eepromWrite()::Failed unlocking page"); + errlCommit(l_pageOpErrl, I2C_COMP_ID); + } + + } + + TRACDCOMP( g_trac_eeprom, + EXIT_MRK"eepromWrite()" ); + + return err; + +} // end eepromWrite + + + +// ------------------------------------------------------------------ +// eepromWriteData +// ------------------------------------------------------------------ +errlHndl_t eepromWriteData( TARGETING::Target * i_target, + void * i_dataToWrite, + size_t i_dataLen, + void * i_byteAddress, + size_t i_byteAddressSize, + eeprom_addr_t i_i2cInfo ) +{ + TRACDCOMP( g_trac_eeprom, + ENTER_MRK"eepromWriteData()"); + errlHndl_t err = NULL; + errlHndl_t err_retryable = NULL; + do + { + /***********************************************************/ + /* Attempt write multiple times ONLY on retryable fails */ + /***********************************************************/ + for (uint8_t retry = 0; + retry <= EEPROM_MAX_RETRIES; + retry++) + { + // Do the actual data write + err = deviceOp( DeviceFW::WRITE, + i_target, + i_dataToWrite, + i_dataLen, + DEVICE_I2C_ADDRESS_OFFSET( + i_i2cInfo.port, + i_i2cInfo.engine, + i_i2cInfo.devAddr, + i_byteAddressSize, + reinterpret_cast<uint8_t*>( + i_byteAddress), + i_i2cInfo.i2cMuxBusSelector, + &(i_i2cInfo.i2cMuxPath) ) ); + + if ( err == NULL ) + { + // Operation completed successfully + // break from retry loop + break; + } + else if ( !errorIsRetryable( err->reasonCode() ) ) + { + // Only retry on errorIsRetryable() failures: break from retry loop + TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData(): I2C " + "Write Non-Retryable fail %d/%d/0x%X, " + "ldl=%d, offset=0x%X, aS=%d, retry=%d", + i_i2cInfo.port, i_i2cInfo.engine, + i_i2cInfo.devAddr, i_dataLen, + i_i2cInfo.offset, i_i2cInfo.addrSize, retry); + + err->collectTrace(EEPROM_COMP_NAME); + + // break from retry loop + break; + } + else // Handle retryable error + { + TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData(): I2C " + "Write retryable fail %d/%d/0x%X, " + "ldl=%d, offset=0x%X, aS=%d, writePageSize = %x", + i_i2cInfo.port, i_i2cInfo.engine, + i_i2cInfo.devAddr, i_dataLen, + i_i2cInfo.offset, i_i2cInfo.addrSize, + i_i2cInfo.writePageSize); + + // Printing mux info separately, if combined, nothing is displayed + char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); + TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData():" + "muxSelector=0x%X, muxPath=%s", + i_i2cInfo.i2cMuxBusSelector, + l_muxPath); + free(l_muxPath); + l_muxPath = nullptr; + + // If op will be attempted again: save error and continue + if ( retry < EEPROM_MAX_RETRIES ) + { + // Only save original retryable error + if ( err_retryable == NULL ) + { + // Save original retryable error + err_retryable = err; + + TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): " + "Error rc=0x%X, eid=0x%X plid=0x%X, " + "tgt=0x%X, retry/MAX=%d/%d. Save error " + "and retry", + err_retryable->reasonCode(), + err_retryable->eid(), + err_retryable->plid(), + TARGETING::get_huid(i_target), + retry, EEPROM_MAX_RETRIES); + + err_retryable->collectTrace(EEPROM_COMP_NAME); + } + else + { + // Add data to original retryable error + TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): " + "Another Retryable Error rc=0x%X, eid=0x%X " + "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. " + "Delete error and retry", + err->reasonCode(), err->eid(), + err->plid(), + TARGETING::get_huid(i_target), + retry, EEPROM_MAX_RETRIES); + + ERRORLOG::ErrlUserDetailsString( + "Another retryable ERROR found") + .addToLog(err_retryable); + + // Delete this new retryable error + delete err; + err = NULL; + } + + // continue to retry + continue; + } + else // no more retries: trace and break + { + TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): " + "Error rc=0x%X, tgt=0x%X. No More Retries " + "(retry/MAX=%d/%d). Returning Error", + err->reasonCode(), + TARGETING::get_huid(i_target), + retry, EEPROM_MAX_RETRIES); + + err->collectTrace(EEPROM_COMP_NAME); + + // break from retry loop + break; + } + } + + } // end of retry loop + /***********************************************************/ + + // Handle saved retryable errors, if any + if (err_retryable) + { + if (err) + { + // commit original retryable error with new err PLID + err_retryable->plid(err->plid()); + TRACFCOMP(g_trac_eeprom, "eepromWriteData(): Committing saved " + "retryable err eid=0x%X with plid of returned err: " + "0x%X", + err_retryable->eid(), err_retryable->plid()); + + ERRORLOG::ErrlUserDetailsTarget(i_target) + .addToLog(err_retryable); + + errlCommit(err_retryable, EEPROM_COMP_ID); + } + else + { + // Since we eventually succeeded, delete original retryable error + TRACFCOMP(g_trac_eeprom, "eepromWriteData(): Op successful, " + "deleting saved retryable err eid=0x%X, plid=0x%X", + err_retryable->eid(), err_retryable->plid()); + + delete err_retryable; + err_retryable = NULL; + } + } + }while( 0 ); + TRACDCOMP( g_trac_eeprom, + EXIT_MRK"eepromWriteData()"); + return err; +} + + + +// ------------------------------------------------------------------ +// eepromPrepareAddress +// ------------------------------------------------------------------ +errlHndl_t eepromPrepareAddress ( TARGETING::Target * i_target, + void * io_buffer, + size_t & o_bufSize, + uint8_t & o_desiredPage, + const eeprom_addr_t & i_i2cInfo ) +{ + errlHndl_t err = NULL; + o_bufSize = 0; + + TRACDCOMP( g_trac_eeprom, + ENTER_MRK"eepromPrepareAddress()" ); + + do + { + + // -------------------------------------------------------------------- + // Currently only supporting I2C devices and that use 0, 1, or 2 bytes + // to set the offset (ie, internal address) into the device. + // -------------------------------------------------------------------- + switch( i_i2cInfo.addrSize ) + { + case TWO_BYTE_ADDR: + o_bufSize = 2; + memset( io_buffer, 0x0, o_bufSize ); + *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFF00ull) >> 8; + *((uint8_t*)io_buffer+1) = (i_i2cInfo.offset & 0x00FFull); + break; + + case ONE_BYTE_ADDR_PAGESELECT: + // If the offset is less than 256 bytes, report page zero, else page 1 + if( i_i2cInfo.offset >= EEPROM_PAGE_SIZE ) + { + o_desiredPage = 1; + } + else + { + o_desiredPage = 0; + } + o_bufSize = 1; + memset( io_buffer, 0x0, o_bufSize ); + *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFFull); + break; + + case ONE_BYTE_ADDR: + o_bufSize = 1; + memset( io_buffer, 0x0, o_bufSize ); + *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFFull); + break; + + case ZERO_BYTE_ADDR: + o_bufSize = 0; + // nothing to do with the buffer in this case + break; + + default: + TRACFCOMP( g_trac_eeprom, + ERR_MRK"eepromPrepareAddress() - Invalid Device " + "Address Size: 0x%08x", i_i2cInfo.addrSize); + + /*@ + * @errortype + * @reasoncode EEPROM_INVALID_DEVICE_TYPE + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid EEPROM_PREPAREADDRESS + * @userdata1 Address Size (aka Device Type) + * @userdata2 EEPROM chip + * @devdesc The Device type not supported (addrSize) + * @custdesc A problem was detected during the IPL of + * the system: Device type not supported. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + EEPROM_PREPAREADDRESS, + EEPROM_INVALID_DEVICE_TYPE, + i_i2cInfo.addrSize, + i_i2cInfo.eepromRole, + true /*Add HB SW Callout*/ ); + + err->collectTrace( EEPROM_COMP_NAME ); + + break; + } + + } while( 0 ); + + TRACDCOMP( g_trac_eeprom, + EXIT_MRK"eepromPrepareAddress()" ); + + return err; +} // end eepromPrepareAddress + +}
\ No newline at end of file diff --git a/src/usr/i2c/eepromdd.H b/src/usr/i2c/eepromdd_hardware.H index 8acf7d8f2..38c7a4d58 100755..100644 --- a/src/usr/i2c/eepromdd.H +++ b/src/usr/i2c/eepromdd_hardware.H @@ -1,11 +1,11 @@ /* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ -/* $Source: src/usr/i2c/eepromdd.H $ */ +/* $Source: src/usr/i2c/eepromdd_hardware.H $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2019 */ +/* Contributors Listed Below - COPYRIGHT 2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -22,86 +22,31 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ -#ifndef __EEPROM_H -#define __EEPROM_H +#ifndef __EEPROMDD_HARDWARE_H +#define __EEPROMDD_HARDWARE_H /** - * @file eepromdd.H + * @file eepromdd_hardware.H * * @brief Provides the interfaces for accessing EEPROMs within - * the system via the I2C device driver. + * the system via the I2C device driver */ -// ---------------------------------------------- -// Includes -// ---------------------------------------------- -#include <i2c/eepromif.H> +#include <i2c/eeprom_const.H> #include <errl/errlentry.H> -namespace EEPROM -{ - -/** -* @brief Enumerations to describe the type of devices to be accessed. -*/ -typedef enum -{ - ZERO_BYTE_ADDR = 0, - ONE_BYTE_ADDR_PAGESELECT = 1, // page select - TWO_BYTE_ADDR = 2, - ONE_BYTE_ADDR = 3, - LAST_DEVICE_TYPE -} eeprom_addr_size_t; -/** - * @brief Structure of common parameters needed by different parts of - * the code. - */ -struct eeprom_addr_t +namespace EEPROM { - uint64_t port; - uint64_t engine; - uint64_t devAddr; - int64_t eepromRole; - uint64_t offset; - eeprom_addr_size_t addrSize; - TARGETING::EntityPath i2cMasterPath; - uint64_t writePageSize; // in bytes - uint64_t devSize_KB; // in kilobytes - uint64_t chipCount; // number of chips making up eeprom device - uint64_t writeCycleTime; // in milliseconds - uint8_t i2cMuxBusSelector; - TARGETING::EntityPath i2cMuxPath; - - /** - * @brief Construct a default eeprom_addr_t - */ - eeprom_addr_t() - : port(0), - engine(0), - devAddr(0), - eepromRole(0), - offset(0), - addrSize(LAST_DEVICE_TYPE), - i2cMasterPath(), - writePageSize(0), - devSize_KB(0), - chipCount(0), - writeCycleTime(0), - i2cMuxBusSelector(I2C_MUX::NOT_APPLICABLE), - i2cMuxPath() - { - } -}; /** * -* @brief Perform an EEPROM access operation. +* @brief Perform an EEPROM access operation on the actual hardware. * * @param[in] i_opType - Operation Type - See DeviceFW::OperationType in * driververif.H * -* @param[in] i_target - Target device. +* @param[in] i_target - Target device associated w/ the EEPROM. * * @param[in/out] io_buffer * INPUT: Pointer to the data that will be written to the target @@ -113,24 +58,22 @@ struct eeprom_addr_t * OUTPUT: Length of buffer that was written, or length of buffer * to be read from target device. * -* @param [in] i_accessType - Access Type - See DeviceFW::AccessType in -* usrif.H +* @param [in/out] io_i2cInfo struct containing information needed to perform +* operation on the given i2c eeprom. NOTE It is expected that +* eepromRole and offset have been filled out in this struct +* prior to passing it into this function * -* @param [in] i_args - This is an argument list for the device driver -* framework. This argument list consists of the chip number of -* the EEPROM to access from the given I2C Master target and the -* internal offset to use on the slave I2C device. +* @pre It is expected that io_i2cInfo.eepromRole will have a valid role set * -* @return errlHndl_t - NULL if successful, otherwise a pointer to the +* @return errlHndl_t - nullptr if successful, otherwise a pointer to the * error log. * */ -errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType, - TARGETING::Target * i_target, - void * io_buffer, - size_t & io_buflen, - int64_t i_accessType, - va_list i_args ); +errlHndl_t eepromPerformOpHW(DeviceFW::OperationType i_opType, + TARGETING::Target * i_target, + void * io_buffer, + size_t & io_buflen, + eeprom_addr_t & io_i2cInfo) ; /** * @@ -146,7 +89,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType, * @param[in/out] i_pageLocked - bool to tell the caller if the page * was successfully locked. * @param[in] i_desiredPage - The page we want to switch to - * @param[in] i_args - This is an argument list for the device driver + * @param[in] i_i2cInfo - This is an argument list for the device driver * framework. This argument list consists of the chip number of * the EEPROM to access from the given I2C Master target and the * internal offset to use on the slave I2C device. @@ -159,10 +102,10 @@ errlHndl_t eepromPageOp( TARGETING::Target * i_target, bool i_lockMutex, bool & io_pageLocked, uint8_t i_desiredPage, - eeprom_addr_t i_i2cInfo ); + const eeprom_addr_t & i_i2cInfo ); -/* +/** * @brief This utility function determines if a read/write straddles * the boundary between EEPROM pages and if so, returns the * parameters to perform 2 operations, one for each page. @@ -183,7 +126,7 @@ bool crossesEepromPageBoundary( uint64_t i_originalOffset, size_t i_originalLen, size_t & io_newLen, size_t & o_pageTwoBuflen, - eeprom_addr_t i_i2cInfo ); + const eeprom_addr_t & i_i2cInfo ); /** @@ -309,48 +252,8 @@ errlHndl_t eepromPrepareAddress ( TARGETING::Target * i_target, void * io_buffer, size_t & o_bufSize, uint8_t & o_desiredPage, - eeprom_addr_t i_i2cInfo); - -/** - * @brief this function will read all of the associated attributes needed - * to access the intended EEPROM. These attributes will be used to - * determine the type of I2C device as well as how to address it via - * the I2C device driver. - * - * @param[in] i_target - Target device. - * - * @param[out] o_i2cInfo - The structure that will contain the attribute data - * read from the target device. - * - * @return errlHndl_t - NULL if successful, otherwise a pointer to the - * error log. - */ -errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target, - eeprom_addr_t & o_i2cInfo ); - -/** - * @brief This function decides whether or not the target passed into the - * EEPROM device driver actually contains the I2C Master engines. If - * not, it will then read the attribute of the target to get the path - * of the target which does contain the I2C Master engine. - * - * @param[in] i_target - The current Target. - * - * @param[in] i_i2cInfo - Structure of I2C parameters needed to execute - * the command to the I2C device driver. - * - * @param[out] o_target - The "new" target that will be used for all operations - * from this point on. It may be == to i_target, or a completely different - * target. BUT, this target will contain the I2C Master engine that will - * allow operations to the target EEPROM. - * - * @return errlHndl_t - NULL if successful, otherwise a pointer to the - * error log. - */ -errlHndl_t eepromGetI2CMasterTarget ( TARGETING::Target * i_target, - eeprom_addr_t i_i2cInfo, - TARGETING::Target * &o_target ); + const eeprom_addr_t & i_i2cInfo); -}; // end EEPROM namespace +} -#endif // __EEPROM_H +#endif
\ No newline at end of file diff --git a/src/usr/i2c/errlud_i2c.C b/src/usr/i2c/errlud_i2c.C index bd27be102..121905e5c 100644 --- a/src/usr/i2c/errlud_i2c.C +++ b/src/usr/i2c/errlud_i2c.C @@ -32,7 +32,6 @@ #include <i2c/i2creasoncodes.H> #include <i2c/eepromddreasoncodes.H> #include <devicefw/driverif.H> -#include "eepromdd.H" #include "i2c.H" namespace I2C diff --git a/src/usr/i2c/errlud_i2c.H b/src/usr/i2c/errlud_i2c.H index 28e8c230d..fb9e752f2 100644 --- a/src/usr/i2c/errlud_i2c.H +++ b/src/usr/i2c/errlud_i2c.H @@ -34,8 +34,7 @@ #include <errl/errluserdetails.H> #include <devicefw/driverif.H> #include "i2c_common.H" -#include "eepromdd.H" - +#include <i2c/eeprom_const.H> namespace I2C { diff --git a/src/usr/i2c/i2c.mk b/src/usr/i2c/i2c.mk index 33d2accda..6d4ef8935 100644 --- a/src/usr/i2c/i2c.mk +++ b/src/usr/i2c/i2c.mk @@ -24,4 +24,7 @@ # IBM_PROLOG_END_TAG # common objects with runtime OBJS += eepromdd.o +OBJS += eepromdd_hardware.o +OBJS += eeprom_utils.o OBJS += errlud_i2c.o +OBJS += $(if $(CONFIG_SUPPORT_EEPROM_CACHING),eepromCache.o) diff --git a/src/usr/i2c/makefile b/src/usr/i2c/makefile index 10e55c9de..535484752 100644 --- a/src/usr/i2c/makefile +++ b/src/usr/i2c/makefile @@ -33,7 +33,6 @@ OBJS += i2c.o OBJS += $(if $(CONFIG_TPMDD),tpmdd.o,) OBJS += fapi_i2c_dd.o OBJS += i2cTargetPres.o -OBJS += $(if $(CONFIG_SUPPORT_EEPROM_CACHING),eepromCache.o) SUBDIRS += test.d SUBDIRS += runtime.d diff --git a/src/usr/i2c/test/eepromddtest.H b/src/usr/i2c/test/eepromddtest.H index 228c0090c..683b2cdb3 100755 --- a/src/usr/i2c/test/eepromddtest.H +++ b/src/usr/i2c/test/eepromddtest.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* Contributors Listed Below - COPYRIGHT 2011,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -37,10 +37,11 @@ #include <errl/errlentry.H> #include <devicefw/driverif.H> #include <i2c/eepromddreasoncodes.H> +#include <i2c/eeprom_const.H> +#include <i2c/eepromif.H> #include <targeting/common/commontargeting.H> #include <pnor/pnorif.H> #include "i2ctest.H" -#include "../eepromdd.H" #include <secureboot/service.H> @@ -183,7 +184,8 @@ class EEPROMTest: public CxxTest::TestSuite testData[i].size, DEVICE_EEPROM_ADDRESS( testData[i].chip, - testData[i].offset)); + testData[i].offset, + EEPROM::AUTOSELECT)); if( err ) { @@ -367,7 +369,8 @@ class EEPROMTest: public CxxTest::TestSuite testBuffer, testBufLen, DEVICE_EEPROM_ADDRESS(SBE_BACKUP, - offset)); + offset, + EEPROM::AUTOSELECT)); if( err ) { @@ -503,7 +506,8 @@ class EEPROMTest: public CxxTest::TestSuite &data, dataSize, DEVICE_EEPROM_ADDRESS( 0x0, - 0x0 ) ); + 0x0 , + EEPROM::AUTOSELECT) ); if( NULL == err ) { @@ -567,7 +571,8 @@ class EEPROMTest: public CxxTest::TestSuite &data, dataSize, DEVICE_EEPROM_ADDRESS( 0x0, - offset ) ); + offset, + EEPROM::AUTOSELECT) ); if( NULL == err ) { @@ -630,7 +635,8 @@ class EEPROMTest: public CxxTest::TestSuite &data, dataSize, DEVICE_EEPROM_ADDRESS( LAST_CHIP_TYPE, - 0x0 ) ); + 0x0, + EEPROM::AUTOSELECT) ); if( NULL == err ) { diff --git a/src/usr/sbe/sbe_update.C b/src/usr/sbe/sbe_update.C index 872015085..f98b8b4d2 100644 --- a/src/usr/sbe/sbe_update.C +++ b/src/usr/sbe/sbe_update.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -2543,7 +2543,7 @@ namespace SBE ///////////////////////////////////////////////////////////////////// errlHndl_t getSeepromSideVersionViaI2c(TARGETING::Target* i_target, - EEPROM::eeprom_chip_types_t i_seepromSide, + EEPROM::EEPROM_ROLE i_seepromSide, sbeSeepromVersionInfo_t& o_info, bool& o_seeprom_ver_ECC_fail) { @@ -2576,7 +2576,8 @@ namespace SBE sbeInfoSize_ECC, DEVICE_EEPROM_ADDRESS( i_seepromSide, - SBE_VERSION_SEEPROM_ADDRESS)); + SBE_VERSION_SEEPROM_ADDRESS, + EEPROM::HARDWARE)); if(err) { @@ -2846,7 +2847,8 @@ errlHndl_t getSeepromSideVersionViaChipOp(TARGETING::Target* i_target, sbeInfoSize_ECC, DEVICE_EEPROM_ADDRESS( io_sbeState.seeprom_side_to_update, - SBE_VERSION_SEEPROM_ADDRESS)); + SBE_VERSION_SEEPROM_ADDRESS, + EEPROM::HARDWARE)); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"updateSeepromSide() - Error " @@ -2871,7 +2873,8 @@ errlHndl_t getSeepromSideVersionViaChipOp(TARGETING::Target* i_target, sbeInfoSize_ECC, DEVICE_EEPROM_ADDRESS( io_sbeState.seeprom_side_to_update, - SBE_VERSION_SEEPROM_ADDRESS)); + SBE_VERSION_SEEPROM_ADDRESS, + EEPROM::HARDWARE)); if(err) { @@ -3082,7 +3085,8 @@ errlHndl_t getSeepromSideVersionViaChipOp(TARGETING::Target* i_target, sbeEccImgSize, DEVICE_EEPROM_ADDRESS( io_sbeState.seeprom_side_to_update, - SBE_IMAGE_SEEPROM_ADDRESS)); + SBE_IMAGE_SEEPROM_ADDRESS, + EEPROM::HARDWARE)); if(err) { @@ -3124,7 +3128,8 @@ errlHndl_t getSeepromSideVersionViaChipOp(TARGETING::Target* i_target, sbeInfoSize_ECC, DEVICE_EEPROM_ADDRESS( io_sbeState.seeprom_side_to_update, - SBE_VERSION_SEEPROM_ADDRESS)); + SBE_VERSION_SEEPROM_ADDRESS, + EEPROM::HARDWARE)); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"updateSeepromSide() - Error " @@ -5654,7 +5659,7 @@ errlHndl_t sbeDoReboot( void ) ///////////////////////////////////////////////////////////////////// errlHndl_t getHwKeyHashFromSbeImage( TARGETING::Target* const i_target, - const EEPROM::eeprom_chip_types_t i_seeprom, + const EEPROM::EEPROM_ROLE i_seeprom, const sbeSeepromSide_t i_bootSide, SHA512_t o_hash, const void * i_image_ptr) // defaults to nullptr @@ -5748,7 +5753,8 @@ errlHndl_t getHwKeyHashFromSbeImage( tmp_data_ECC, size, DEVICE_EEPROM_ADDRESS(i_seeprom, - seeprom_offset)); + seeprom_offset, + EEPROM::HARDWARE)); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getHwKeyHashFromSbeImage() " @@ -5925,7 +5931,8 @@ errlHndl_t getHwKeyHashFromSbeImage( size, DEVICE_EEPROM_ADDRESS( i_seeprom, - seeprom_offset)); + seeprom_offset, + EEPROM::HARDWARE)); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getHwKeyHashFromSbeImage() " diff --git a/src/usr/sbe/test/sbeupdatetest.H b/src/usr/sbe/test/sbeupdatetest.H index 7f582c6da..cf482c053 100644 --- a/src/usr/sbe/test/sbeupdatetest.H +++ b/src/usr/sbe/test/sbeupdatetest.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -842,12 +842,12 @@ class SBEUpdateTest: public CxxTest::TestSuite { // Inputs uint8_t i_situation; - SBE::sbeSeepromSide_t i_cur; // current_seeprom_side + SBE::sbeSeepromSide_t i_cur; // current_seeprom_side uint8_t i_flags; // mvpdSbKeyword.flags // Expected Output sbeUpdateActions_t o_update_actions; - EEPROM::eeprom_chip_types_t o_seeprom; + EEPROM::EEPROM_ROLE o_seeprom; uint8_t o_flags; // mvpdSbKeyword.flags } testData[] = diff --git a/src/usr/targeting/common/xmltohb/xmltohb.pl b/src/usr/targeting/common/xmltohb/xmltohb.pl index 907e70359..50428f8c2 100755 --- a/src/usr/targeting/common/xmltohb/xmltohb.pl +++ b/src/usr/targeting/common/xmltohb/xmltohb.pl @@ -6,7 +6,7 @@ # # OpenPOWER HostBoot Project # -# Contributors Listed Below - COPYRIGHT 2012,2018 +# Contributors Listed Below - COPYRIGHT 2012,2019 # [+] International Business Machines Corp. # # @@ -3864,6 +3864,8 @@ sub writeTargetErrlHFile { print $outFile "#ifndef ERRL_UDTARGET_H\n"; print $outFile "#define ERRL_UDTARGET_H\n"; print $outFile "\n"; + print $outFile "#include <string.h>\n"; + print $outFile "\n"; print $outFile "namespace ERRORLOG\n"; print $outFile "{\n"; print $outFile "typedef struct TargetLabel_t\n"; diff --git a/src/usr/vpd/ipvpd.C b/src/usr/vpd/ipvpd.C index 877b91283..241c8e7cf 100644 --- a/src/usr/vpd/ipvpd.C +++ b/src/usr/vpd/ipvpd.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -1792,7 +1792,7 @@ errlHndl_t IpVpdFacade::fetchDataFromEeprom ( uint64_t i_byteAddr, i_numBytes, DEVICE_EEPROM_ADDRESS( EEPROM::VPD_PRIMARY, - i_byteAddr ) ); + i_byteAddr, EEPROM::AUTOSELECT ) ); if( err ) { break; @@ -2230,7 +2230,8 @@ errlHndl_t IpVpdFacade::writeKeyword ( const char * i_keywordName, keywordSize, DEVICE_EEPROM_ADDRESS( EEPROM::VPD_PRIMARY, - i_offset+byteAddr ) ); + i_offset+byteAddr, + EEPROM::AUTOSELECT) ); if( err ) { break; diff --git a/src/usr/vpd/spd.C b/src/usr/vpd/spd.C index 0a5bd7245..b57297df0 100644 --- a/src/usr/vpd/spd.C +++ b/src/usr/vpd/spd.C @@ -515,7 +515,8 @@ errlHndl_t spdFetchData ( uint64_t i_byteAddr, i_numBytes, DEVICE_EEPROM_ADDRESS( EEPROM::VPD_PRIMARY, - i_byteAddr ) ); + i_byteAddr, + EEPROM::AUTOSELECT) ); if( err ) { TRACFCOMP(g_trac_spd, @@ -596,7 +597,8 @@ errlHndl_t spdWriteData ( uint64_t i_offset, i_numBytes, DEVICE_EEPROM_ADDRESS( EEPROM::VPD_PRIMARY, - i_offset ) ); + i_offset, + EEPROM::AUTOSELECT) ); if( err ) { break; |