summaryrefslogtreecommitdiffstats
path: root/src/usr/errl
diff options
context:
space:
mode:
authorJaymes Wilks <mjwilks@us.ibm.com>2018-08-17 11:24:21 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-11-12 09:00:37 -0600
commit87adeec286402eb648f14d274382fb8b84351467 (patch)
tree62f3c86906eac47753f862e8147af53a469e5d3f /src/usr/errl
parentd83a4ee8495c5ad4b823c26b1a09a3c886882494 (diff)
downloadtalos-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.mk1
-rw-r--r--src/usr/errl/errlentry.C7
-rw-r--r--src/usr/errl/errli2c.C279
-rw-r--r--src/usr/errl/errlmanager_common.C8
-rw-r--r--src/usr/errl/plugins/errludcallout.H4
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
}
OpenPOWER on IntegriCloud