diff options
author | Matt Spinler <spinler@us.ibm.com> | 2019-10-09 10:08:43 -0500 |
---|---|---|
committer | Matt Spinler <spinler@us.ibm.com> | 2019-10-22 14:09:56 +0000 |
commit | 90b4a0a0682cb596fdaf0eabbaccd2735e52bd89 (patch) | |
tree | 4dad7d467d899035af02a6d77df38eea83b2ceda | |
parent | 5b3a11db9c1f9715cc6371ecdcaa6bc54343ecc0 (diff) | |
download | phosphor-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.cpp | 53 | ||||
-rw-r--r-- | extensions/openpower-pels/mru.hpp | 122 | ||||
-rw-r--r-- | extensions/openpower-pels/openpower-pels.mk | 1 | ||||
-rw-r--r-- | test/openpower-pels/Makefile.include | 9 | ||||
-rw-r--r-- | test/openpower-pels/mru_test.cpp | 59 |
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); +} |