summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Spinler <spinler@us.ibm.com>2019-10-09 10:08:43 -0500
committerMatt Spinler <spinler@us.ibm.com>2019-10-22 14:09:56 +0000
commit90b4a0a0682cb596fdaf0eabbaccd2735e52bd89 (patch)
tree4dad7d467d899035af02a6d77df38eea83b2ceda
parent5b3a11db9c1f9715cc6371ecdcaa6bc54343ecc0 (diff)
downloadphosphor-logging-90b4a0a0682cb596fdaf0eabbaccd2735e52bd89.tar.gz
phosphor-logging-90b4a0a0682cb596fdaf0eabbaccd2735e52bd89.zip
PEL: MRU callout SRC substructure
This substructure is part of the callout subsection in the SRC section of a PEL, and contains information about Manufacturing Replaceable Units (MRUs). MRUs are components on a parent FRU (Field Replaceable Unit) that may be able to be replaced in a manufacturing environment, hence the name. This substructure includes a list of <priority, MRU ID> pairs, where the priority is the same priority value type as used elsewhere in the SRC section ('H', 'M', 'L', etc), and the MRU ID is a 4B ID that development will tell manufacturing the meanings of. This commit only adds support for creating an object from a flattened PEL, such as one that comes down from the host. A future commit will handle creating it from scratch for BMC errors. Signed-off-by: Matt Spinler <spinler@us.ibm.com> Change-Id: I6352e1a3cb84db0516902786faca4c387afef411
-rw-r--r--extensions/openpower-pels/mru.cpp53
-rw-r--r--extensions/openpower-pels/mru.hpp122
-rw-r--r--extensions/openpower-pels/openpower-pels.mk1
-rw-r--r--test/openpower-pels/Makefile.include9
-rw-r--r--test/openpower-pels/mru_test.cpp59
5 files changed, 244 insertions, 0 deletions
diff --git a/extensions/openpower-pels/mru.cpp b/extensions/openpower-pels/mru.cpp
new file mode 100644
index 0000000..89e0cfe
--- /dev/null
+++ b/extensions/openpower-pels/mru.cpp
@@ -0,0 +1,53 @@
+#include "mru.hpp"
+
+#include <phosphor-logging/log.hpp>
+
+namespace openpower
+{
+namespace pels
+{
+namespace src
+{
+
+using namespace phosphor::logging;
+
+MRU::MRU(Stream& pel)
+{
+ pel >> _type >> _size >> _flags >> _reserved4B;
+
+ size_t numMRUs = _flags & 0xF;
+
+ for (size_t i = 0; i < numMRUs; i++)
+ {
+ MRUCallout mru;
+ pel >> mru.priority;
+ pel >> mru.id;
+ _mrus.push_back(std::move(mru));
+ }
+
+ size_t actualSize = sizeof(_type) + sizeof(_size) + sizeof(_flags) +
+ sizeof(_reserved4B) +
+ (sizeof(MRUCallout) * _mrus.size());
+ if (_size != actualSize)
+ {
+ log<level::WARNING>("MRU callout section in PEL has listed size that "
+ "doesn't match actual size",
+ entry("SUBSTRUCTURE_SIZE=%lu", _size),
+ entry("NUM_MRUS=%lu", _mrus.size()),
+ entry("ACTUAL_SIZE=%lu", actualSize));
+ }
+}
+
+void MRU::flatten(Stream& pel)
+{
+ pel << _type << _size << _flags << _reserved4B;
+
+ for (auto& mru : _mrus)
+ {
+ pel << mru.priority;
+ pel << mru.id;
+ }
+}
+} // namespace src
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/mru.hpp b/extensions/openpower-pels/mru.hpp
new file mode 100644
index 0000000..8ad3e3c
--- /dev/null
+++ b/extensions/openpower-pels/mru.hpp
@@ -0,0 +1,122 @@
+#pragma once
+
+#include "stream.hpp"
+
+namespace openpower
+{
+namespace pels
+{
+namespace src
+{
+
+/**
+ * @class MRU
+ *
+ * This represents the MRU (Manufacturing Replaceable Unit)
+ * substructure in the callout subsection of the SRC PEL section.
+ *
+ * Manufacturing replaceable units have a finer granularity than
+ * a field replaceable unit, such as a chip on a card, and are
+ * intended to be used during manufacturing.
+ *
+ * This substructure can contain up to 128 MRU callouts, each
+ * containing a MRU ID and a callout priority value.
+ */
+class MRU
+{
+ public:
+ /**
+ * @brief A single MRU callout, which contains a priority
+ * and a MRU ID.
+ *
+ * The priority value is the same priority type character
+ * value as in the parent callout structure. For alignment
+ * purposes it is a 4 byte field, though only the LSB contains
+ * the priority value.
+ */
+ struct MRUCallout
+ {
+ uint32_t priority;
+ uint32_t id;
+ };
+
+ MRU() = delete;
+ ~MRU() = default;
+ MRU(const MRU&) = default;
+ MRU& operator=(const MRU&) = default;
+ MRU(MRU&&) = default;
+ MRU& operator=(MRU&&) = default;
+
+ /**
+ * @brief Constructor
+ *
+ * Fills in this class's data fields from the stream.
+ *
+ * @param[in] pel - the PEL data stream
+ */
+ explicit MRU(Stream& pel);
+
+ /**
+ * @brief Flatten the object into the stream
+ *
+ * @param[in] stream - The stream to write to
+ */
+ void flatten(Stream& pel);
+
+ /**
+ * @brief Returns the size of this structure when flattened into a PEL
+ *
+ * @return size_t - The size of the section
+ */
+ size_t flattenedSize() const
+ {
+ return _size;
+ }
+
+ /**
+ * @brief Returns the contained MRU callouts.
+ *
+ * @return const std::vector<MRUCallout>& - The MRUs
+ */
+ const std::vector<MRUCallout>& mrus() const
+ {
+ return _mrus;
+ }
+
+ /**
+ * @brief The type identifier value of this structure.
+ */
+ static const uint16_t substructureType = 0x4D52; // "MR"
+
+ private:
+ /**
+ * @brief The callout substructure type field. Will be 'MR'.
+ */
+ uint16_t _type;
+
+ /**
+ * @brief The size of this callout structure.
+ */
+ uint8_t _size;
+
+ /**
+ * @brief The flags byte of this substructure.
+ *
+ * 0x0Y: Y = number of MRU callouts
+ */
+ uint8_t _flags;
+
+ /**
+ * @brief Reserved 4 bytes
+ */
+ uint32_t _reserved4B;
+
+ /*
+ * @brief The MRU callouts
+ */
+ std::vector<MRUCallout> _mrus;
+};
+
+} // namespace src
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk
index 550530c..fdc998d 100644
--- a/extensions/openpower-pels/openpower-pels.mk
+++ b/extensions/openpower-pels/openpower-pels.mk
@@ -8,6 +8,7 @@ phosphor_log_manager_SOURCES += \
extensions/openpower-pels/generic.cpp \
extensions/openpower-pels/log_id.cpp \
extensions/openpower-pels/manager.cpp \
+ extensions/openpower-pels/mru.cpp \
extensions/openpower-pels/mtms.cpp \
extensions/openpower-pels/paths.cpp \
extensions/openpower-pels/pce_identity.cpp \
diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include
index 74e33c6..e54bce8 100644
--- a/test/openpower-pels/Makefile.include
+++ b/test/openpower-pels/Makefile.include
@@ -8,6 +8,7 @@ check_PROGRAMS += \
fru_identity_test \
generic_section_test \
log_id_test \
+ mru_test \
mtms_test \
pce_identity_test \
pel_test \
@@ -218,3 +219,11 @@ pce_identity_test_LDADD = \
$(top_builddir)/extensions/openpower-pels/pce_identity.o \
$(top_builddir)/extensions/openpower-pels/mtms.o
pce_identity_test_LDFLAGS = $(test_ldflags)
+
+mru_test_SOURCES = %reldir%/mru_test.cpp
+mru_test_CPPFLAGS = $(test_cppflags)
+mru_test_CXXFLAGS = $(test_cxxflags)
+mru_test_LDADD = \
+ $(test_ldadd) \
+ $(top_builddir)/extensions/openpower-pels/mru.o
+mru_test_LDFLAGS = $(test_ldflags)
diff --git a/test/openpower-pels/mru_test.cpp b/test/openpower-pels/mru_test.cpp
new file mode 100644
index 0000000..38e80f9
--- /dev/null
+++ b/test/openpower-pels/mru_test.cpp
@@ -0,0 +1,59 @@
+#include "extensions/openpower-pels/mru.hpp"
+
+#include <gtest/gtest.h>
+
+using namespace openpower::pels;
+using namespace openpower::pels::src;
+
+TEST(MRUTest, TestConstructor)
+{
+ std::vector<uint8_t> data{
+ 'M', 'R', 0x28, 0x04, // ID, size, flags
+ 0x00, 0x00, 0x00, 0x00, // Reserved
+ 0x00, 0x00, 0x00, 'H', // priority for MRU ID 0
+ 0x01, 0x01, 0x01, 0x01, // MRU ID 0
+ 0x00, 0x00, 0x00, 'M', // priority for MRU ID 1
+ 0x02, 0x02, 0x02, 0x02, // MRU ID 1
+ 0x00, 0x00, 0x00, 'L', // priority for MRU ID 2
+ 0x03, 0x03, 0x03, 0x03, // MRU ID 2
+ 0x00, 0x00, 0x00, 'H', // priority for MRU ID 3
+ 0x04, 0x04, 0x04, 0x04, // MRU ID 3
+ };
+
+ Stream stream{data};
+
+ MRU mru{stream};
+
+ EXPECT_EQ(mru.flattenedSize(), data.size());
+ EXPECT_EQ(mru.mrus().size(), 4);
+
+ EXPECT_EQ(mru.mrus().at(0).priority, 'H');
+ EXPECT_EQ(mru.mrus().at(0).id, 0x01010101);
+ EXPECT_EQ(mru.mrus().at(1).priority, 'M');
+ EXPECT_EQ(mru.mrus().at(1).id, 0x02020202);
+ EXPECT_EQ(mru.mrus().at(2).priority, 'L');
+ EXPECT_EQ(mru.mrus().at(2).id, 0x03030303);
+ EXPECT_EQ(mru.mrus().at(3).priority, 'H');
+ EXPECT_EQ(mru.mrus().at(3).id, 0x04040404);
+
+ // Now flatten
+ std::vector<uint8_t> newData;
+ Stream newStream{newData};
+
+ mru.flatten(newStream);
+ EXPECT_EQ(data, newData);
+}
+
+TEST(MRUTest, TestBadData)
+{
+ // 4 MRUs expected, but only 1
+ std::vector<uint8_t> data{
+ 'M', 'R', 0x28, 0x04, // ID, size, flags
+ 0x00, 0x00, 0x00, 0x00, // Reserved
+ 0x00, 0x00, 0x00, 'H', // priority 0
+ 0x01, 0x01, 0x01, 0x01, // MRU ID 0
+ };
+
+ Stream stream{data};
+ EXPECT_THROW(MRU mru{stream}, std::out_of_range);
+}
OpenPOWER on IntegriCloud