diff options
author | Jaymes Wilks <mjwilks@us.ibm.com> | 2018-08-17 11:24:21 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2018-11-12 09:00:37 -0600 |
commit | 87adeec286402eb648f14d274382fb8b84351467 (patch) | |
tree | 62f3c86906eac47753f862e8147af53a469e5d3f /src/usr/errl | |
parent | d83a4ee8495c5ad4b823c26b1a09a3c886882494 (diff) | |
download | talos-hostboot-87adeec286402eb648f14d274382fb8b84351467.tar.gz talos-hostboot-87adeec286402eb648f14d274382fb8b84351467.zip |
Support openpower-specific I2C device callouts
This change supports the openpower path for adding I2C device
callouts to error logs. The process works as follows:
- Create an I2C device lookup table on first use of I2C callout
- Use that table to map I2C info to the actual device to callout
- Callout any other I2C devices on the bus with lesser priority
- If no I2C match found, callout the I2C master instead
- If an I2C device was found, callout the I2C master as low
Change-Id: Ib7b248ae60e7e834d6165bbdf4bd9b776ea2421b
RTC:94872
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/64833
Reviewed-by: Michael Baiocchi <mbaiocch@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/errl')
-rw-r--r-- | src/usr/errl/errl.mk | 1 | ||||
-rw-r--r-- | src/usr/errl/errlentry.C | 7 | ||||
-rw-r--r-- | src/usr/errl/errli2c.C | 279 | ||||
-rw-r--r-- | src/usr/errl/errlmanager_common.C | 8 | ||||
-rw-r--r-- | src/usr/errl/plugins/errludcallout.H | 4 |
5 files changed, 296 insertions, 3 deletions
diff --git a/src/usr/errl/errl.mk b/src/usr/errl/errl.mk index ce1c5c0e8..8cab37324 100644 --- a/src/usr/errl/errl.mk +++ b/src/usr/errl/errl.mk @@ -40,3 +40,4 @@ OBJS += errludcallout.o OBJS += errludsensor.o OBJS += errludstate.o OBJS += errlmanager_common.o +OBJS += errli2c.o diff --git a/src/usr/errl/errlentry.C b/src/usr/errl/errlentry.C index ad95bc4dd..7f7c9a5b0 100644 --- a/src/usr/errl/errlentry.C +++ b/src/usr/errl/errlentry.C @@ -47,6 +47,7 @@ #include <errl/errluserdetails.H> #include <errl/errludattribute.H> #include <errl/errludstate.H> +#include <errl/errli2c.H> #include <trace/interface.H> #include <config.h> @@ -64,10 +65,12 @@ #include <attributeenums.H> #include "errlentry_consts.H" #include <util/misc.H> + #ifdef CONFIG_BMC_IPMI #include <ipmi/ipmisensor.H> #include <errl/errludsensor.H> #endif + // Hostboot Image ID string extern char hbi_ImageId; @@ -2203,10 +2206,12 @@ void ErrlEntry::addI2cDeviceCallout(const TARGETING::Target *i_i2cMaster, ep = nullptr; } - } while (0); + handleI2cDeviceCalloutWithinHostboot(this, i_i2cMaster, i_engine, i_port, i_address, i_priority); + } while (0); } // addI2cDeviceCallout + } // End namespace diff --git a/src/usr/errl/errli2c.C b/src/usr/errl/errli2c.C new file mode 100644 index 000000000..92229a65a --- /dev/null +++ b/src/usr/errl/errli2c.C @@ -0,0 +1,279 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/errl/errli2c.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2018 */ +/* [+] 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 */ +/*****************************************************************************/ +// I n c l u d e s +/*****************************************************************************/ +#include <stdio.h> +#include <errl/errli2c.H> +#include <errl/errlmanager.H> +#include <trace/interface.H> +#include <hwas/common/hwasCallout.H> +#include <hwas/common/deconfigGard.H> +#include <targeting/common/targetservice.H> +#include <targeting/common/utilFilter.H> +#include <config.h> +#include <attributeenums.H> +#include <i2c/eepromif.H> + +using namespace ERRORLOG; +using namespace HWAS; + +namespace ERRORLOG +{ + +// Trace definition +extern trace_desc_t* g_trac_errl; + +uint8_t I2cDevInfos::getDepth(const TARGETING::Target* i_target) const +{ + return i_target->getAttr<TARGETING::ATTR_PHYS_PATH>().size(); +} + +I2cDevInfos::I2cDevInfos() +{ + auto& tS = TARGETING::targetService(); + + TARGETING::TargetRangeFilter l_targetFilter(tS.begin(), tS.end(), nullptr); + + // gather up all the matching info and store in the vector + for(;l_targetFilter; ++l_targetFilter) + { + const TARGETING::Target* l_tgt = (*l_targetFilter); + // Looking to see if we have any info about VPD or SBE Seeproms + { + TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO_type d; // local scope + if (l_tgt->tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO>(d)) + { + iv_i2cdvs.push_back({d.i2cMasterPath, d.engine, d.port, + d.devAddr, d.chipCount, EEPROM::VPD_PRIMARY, + l_tgt, getDepth(l_tgt)}); + } + } + { + TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO_type d; // local scope + if (l_tgt->tryGetAttr<TARGETING::ATTR_EEPROM_SBE_PRIMARY_INFO>(d)) + { + // String literal is used for comparison below, must stay sync'd + iv_i2cdvs.push_back({d.i2cMasterPath, d.engine, d.port, + d.devAddr, d.chipCount, EEPROM::SBE_PRIMARY, + l_tgt, getDepth(l_tgt)}); + } + } + { + TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO_type d; // local scope + if (l_tgt->tryGetAttr<TARGETING::ATTR_EEPROM_VPD_BACKUP_INFO>(d)) + { + // String literal is used for comparison below, must stay sync'd + iv_i2cdvs.push_back({d.i2cMasterPath, d.engine, d.port, + d.devAddr, d.chipCount, EEPROM::VPD_BACKUP, + l_tgt, getDepth(l_tgt)}); + } + } + { + TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO_type d; // local scope + if (l_tgt->tryGetAttr<TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO>(d)) + { + // String literal is used for comparison below, must stay sync'd + iv_i2cdvs.push_back({d.i2cMasterPath, d.engine, d.port, + d.devAddr, d.chipCount, EEPROM::SBE_BACKUP, + l_tgt, getDepth(l_tgt)}); + } + } + // try for a TPM + { + TARGETING::ATTR_TPM_INFO_type t; + if (l_tgt->tryGetAttr<TARGETING::ATTR_TPM_INFO>(t)) + { + // String literal is used for comparison below, must stay sync'd + iv_i2cdvs.push_back({t.i2cMasterPath, t.engine, t.port, + t.devAddrLocality0, 0, + EEPROM::INVALID_CHIP_TYPE, l_tgt, + getDepth(l_tgt)}); + } + } + } +} + + +void handleI2cDeviceCalloutWithinHostboot( + errlHndl_t i_errl, + const TARGETING::Target *i_i2cMaster, + const uint8_t i_engine, + const uint8_t i_port, + const uint8_t i_address, + const HWAS::callOutPriority i_priority) +{ + do { + + assert(i_errl != nullptr, "Bug! Error log handle pointer passed is null"); + assert(i_i2cMaster != nullptr, "Bug! I2C master target passed is null"); + assert(i_priority >= HWAS::SRCI_PRIORITY_LOW && + i_priority <= HWAS::SRCI_PRIORITY_HIGH, "Bug! Bad priority given"); + + auto& tS = TARGETING::targetService(); + + auto l_devFound = false; + + const auto l_i2cmPhysPath = i_i2cMaster->getAttr<TARGETING::ATTR_PHYS_PATH>(); + + // determine default priority to be one below what was passed in, or if + // LOW was passed in, then LOW. Its use is described below. + auto l_defaultPriority = HWAS::SRCI_PRIORITY_LOW; + if (i_priority == HWAS::SRCI_PRIORITY_HIGH) + { + l_defaultPriority = HWAS::SRCI_PRIORITY_MED; + } + + // list of devices to search from + auto i2cdvs = I2cDevInfos::getInstance().getDevList(); + + // we delay adding hardware callouts until the end so that we + // can eliminate duplicate targets representing the same device + std::vector<I2cMatchingInfo_t> i2chwcos; + + // try to find a device match in the list of matching infos + for (auto& i2cd : i2cdvs) + { + TRACDCOMP(g_trac_errl, "handleI2cDeviceCalloutWithinHostboot: chipType %d Engine=%d, Port=%d, addr=0x%X, i2cMasterHuid=0x%X huid=0x%X w/ %d chips ...", i2cd.chipType, i2cd.engine, i2cd.port, i2cd.devAddr, TARGETING::get_huid(tS.toTarget(i2cd.i2cMasterPath)), TARGETING::get_huid(i2cd.tgt), i2cd.chipCount); + + // match the master path, engine and port + if (l_i2cmPhysPath == i2cd.i2cMasterPath && + i_engine == i2cd.engine && + i_port == i2cd.port) + { + // all devices on the bus default to one notch below the passed + // in priority unless LOW was passed in (see calculation above) + auto l_priority = l_defaultPriority; + + // if the device is its own i2c master + if (i_i2cMaster == i2cd.tgt) + { + // go the part callout route + + // set to the passed in priority if the address is in range + // otherwise leave as default priority + const auto maxAddr = i2cd.devAddr + + (i2cd.chipCount * EEPROM::EEPROM_DEVADDR_INC); + if (i_address >= i2cd.devAddr && i_address < maxAddr) + { + l_priority = i_priority; // priority passed in + l_devFound = true; + } + TRACDCOMP(g_trac_errl, "handleI2cDeviceCalloutWithinHostboot: Match found! Adding part callout for chipType %d Engine=%d, Port=%d, addr=0x%X, i2cMasterHuid=0x%X w/ %d chips", i2cd.chipType, i2cd.engine, i2cd.port, i2cd.devAddr, TARGETING::get_huid(i2cd.tgt), i2cd.chipCount); + + // add VPD or SBE part callout depending on chip type + i_errl->addPartCallout(i2cd.tgt, + (i2cd.chipType==EEPROM::VPD_PRIMARY || + i2cd.chipType==EEPROM::VPD_BACKUP)? + HWAS::VPD_PART_TYPE: + HWAS::SBE_SEEPROM_PART_TYPE, + l_priority, + HWAS::NO_DECONFIG, + HWAS::GARD_NULL); + } + else + { + // go the HW callout route + + // first check to see if the device is a duplicate + auto dupItr = std::find_if(i2chwcos.begin(),i2chwcos.end(), + [&i2cd](const I2cMatchingInfo_t & matchedBefore) + { + // return true if the current device matches something we + // have matched previously + return i2cd.i2cMasterPath == matchedBefore.i2cMasterPath && + i2cd.engine == matchedBefore.engine && + i2cd.port == matchedBefore.port && + i2cd.devAddr == matchedBefore.devAddr; + }); + + TRACDCOMP(g_trac_errl, "handleI2cDeviceCalloutWithinHostboot: i2cdev chipType=%d Engine=%d, Port=%d, addr=0x%X, i2cHuid=0x%X, i2cd.targetAncestryDepth=%d", i2cd.chipType, i2cd.engine, i2cd.port, i2cd.devAddr, TARGETING::get_huid(i2cd.tgt), i2cd.targetAncestryDepth); + + if(dupItr == i2chwcos.end()) + { + // not there so add the match + i2chwcos.push_back(i2cd); + } + else + { + // dereference the duplicate device from its iterator + auto dupDev = *dupItr; + + TRACDCOMP(g_trac_errl, "handleI2cDeviceCalloutWithinHostboot: dupdev chipType=%d Engine=%d, Port=%d, addr=0x%X, i2cHuid=0x%X, dupDev.targetAncestryDepth=%d", dupDev.chipType, dupDev.engine, dupDev.port, dupDev.devAddr, TARGETING::get_huid(dupDev.tgt), dupDev.targetAncestryDepth); + + // we need to replace it if we found a device with more + // seniority (in other words less depth) than the duplicate + if (dupDev.targetAncestryDepth > i2cd.targetAncestryDepth) + { + i2chwcos.erase(dupItr); // remove the old + i2chwcos.push_back(i2cd); // add the new + } + } + } + } + } + + // now that we know there are no duplicates add the HW callouts in 2nd pass + for (auto& i2cd : i2chwcos) + { + // all devices on the bus default to one notch below the passed + // in priority unless LOW was passed in (see calculation above) + auto l_priority = l_defaultPriority; + + // set to the passed in priority for exact device address matches + // otherwise leave as default priority + + if (i_address == i2cd.devAddr) + { + l_priority = i_priority; + l_devFound = true; + } + TRACDCOMP(g_trac_errl, "handleI2cDeviceCalloutWithinHostboot: Match found! Adding Hw callout for huid 0x%X", TARGETING::get_huid(i2cd.tgt)); + i_errl->addHwCallout(i2cd.tgt, + l_priority, + HWAS::NO_DECONFIG, + HWAS::GARD_NULL); + + } + + // callout i2c master as the priorty passed in if nothing else was found + // otherwise callout as low to let the device found to take precedence + i_errl->addHwCallout( i_i2cMaster, + l_devFound? HWAS::SRCI_PRIORITY_LOW: + i_priority, + HWAS::NO_DECONFIG, + HWAS::GARD_NULL ); + + } while ( 0 ); +} + + +I2cDevInfos& I2cDevInfos::getInstance() +{ + return Singleton<I2cDevInfos>::instance(); +} + +} // End namespace + diff --git a/src/usr/errl/errlmanager_common.C b/src/usr/errl/errlmanager_common.C index 77cd5594a..e1e965e5a 100644 --- a/src/usr/errl/errlmanager_common.C +++ b/src/usr/errl/errlmanager_common.C @@ -657,6 +657,14 @@ void ErrlManager::sendErrLogToBmc(errlHndl_t &io_err, bool i_sendSels) l_calloutToAdd.procedure = HWAS::EPUB_PRC_EIBUS_ERROR; } + // I2C device callouts don't map to anything useful in the + // IPMI world. They do come with a more IPMI-friendly + // callout that follows after, so we can skip to the next. + if (l_ud->type == HWAS::I2C_DEVICE_CALLOUT) + { + continue; + } + // if this callout is higher than any previous callout if (l_ud->priority > l_priority) { diff --git a/src/usr/errl/plugins/errludcallout.H b/src/usr/errl/plugins/errludcallout.H index f5ef563b7..e8bb364e9 100644 --- a/src/usr/errl/plugins/errludcallout.H +++ b/src/usr/errl/plugins/errludcallout.H @@ -222,13 +222,13 @@ case HWAS::_type: i_parser.PrintString( "Bus Type", #_type); break; } case HWAS::I2C_DEVICE_CALLOUT: { - i_parser.PrintString( "Callout type", "I2c Device Callout"); + i_parser.PrintString( "Callout type", "I2C Device Callout"); i_parser.PrintNumber( "Engine","0x%.2x", pData->engine ); i_parser.PrintNumber( "Port","0x%.2x", pData->port ); i_parser.PrintNumber( "DevAddr","0x%.2x", pData->address ); uint8_t *l_ptr = reinterpret_cast<uint8_t *>(pData+1); - printEntityPath(l_ptr, i_parser, "Target"); + printEntityPath(l_ptr, i_parser, "I2C Master"); break; // I2C_DEVICE_CALLOUT } |